7

0.213123たとえば、値or 0.0、または、を表すことができる数値タイプを探していますが、および1.0などの範囲外の値を拒否しています。その目的に合う特定のタイプがありますか、そして特定の範囲に数を制限するための最適な一般的なアプローチは何ですか?-0.21231.2312

もちろん、最初に頭に浮かぶ答えは次のとおりです。使用するだけですDoubleが、Haskellの型システムに甘やかされて、型レベルでプログラムを最大限に保護することに慣れてきました。

4

4 に答える 4

5

深刻な提案

適切なビットサイズの単語の周りにニュータイプラッパー(およびスマートコンストラクター)を使用できます。

newtype SmallFrac = SF Word64

-- Example conversion (You'd actually want to make
-- instances of common classes, I assume)
sfToDouble :: SmallFrac -> Double
sfToDouble (SF x) = fromIntegral x / fromIntegral (maxBound `asTypeOf` x)

instance Show SmallFrac where
    show = show . sfToDouble

乗算と除算の実装は、必要以上にコストがかかる可能性がありますが、少なくとも加算は簡単で(モジュロでオーバーフロー/アンダーフローから保護)、操作は必要ないと主張します。

あまり役に立たない提案

必要なのが1と0の間に存在する値を表すシンボルだけである場合は、dave4420の提案を採用し、ユニットタイプを指定してください。

newtype SmallFrac = SF ()

このタイプの操作はなく、などの他のタイプのインタレストとの間の変換もありませんDoubleが、これは前述の要求を満たします。

于 2013-02-22T21:07:05.503 に答える
4

標準ではありません。1つ作成する必要があります-スマートコンストラクターをお勧めします。ただし、このような型がサポートする数値演算はごくわずかであることに注意してください。これらを追加してセットに保持したり、否定したりすることはできないため、Numインスタンスに対してアドバイスします。Monoid乗算のAは合理的です。

于 2013-02-22T19:06:14.343 に答える
3

ダブルに基づく表現

newtype Rep1 = Rep1 Double

checkRange :: Double -> Maybe Double
checkRange x
  | 0 < x && x < 1 = Just x
  | otherwise = Nothing

toRep1 :: Double -> Maybe Rep1
toRep1 x = Rep1 . (\x -> tan $ (x-0.5) * pi) <$> checkRange x

fromRep1 :: Rep1 -> Double
fromRep1 (Rep1 x) = atan x / pi + 0.5

整数に基づく表現

data Rep2 = Rep2 Integer Integer

fromRep2 :: Rep2 -> Double
fromRep2 (Rep2 a b) = fromIntegral (abs a) / fromIntegral (abs a + abs b + 1)

toRep2 :: Double -> Maybe Rep2
toRep2 = error "left to the reader"
于 2013-02-22T21:14:11.063 に答える
2

スマートコンストラクターパターンのバリエーション。

これはやり過ぎかもしれません。

{-# LANGUAGE TemplateHaskell #-}
module Foo (Foo(), doubleFromFoo,
            maybeFooFromDouble, unsafeFooFromDouble, thFooFromDouble)
where
import Language.Haskell.TH

とにかく、標準newtype..。

newtype Foo = Foo Double

外出Doubleは簡単です...

doubleFromFoo :: Foo -> Double
doubleFromFoo (Foo x) = x

実行Double時に入力すると、実行時チェックが発生しますが、それを回避することはできません...

maybeFooFromDouble :: Double -> Maybe Foo
maybeFooFromDouble x
        | 0 <= x && x <= 1 = Just (Foo x)
        | otherwise        = Nothing

...あなたが安全でないことに満足していない限り(そして、すべての使用unsafeFooFromDoubleが実際に安全であることを強制するいくつかの社会的手段を持っていない限り)...

unsafeFooFromDouble :: Double -> Foo
unsafeFooFromDouble = Foo

ただし、コンパイル時定数の場合は、実行時のオーバーヘッドなしで、コンパイル時にチェックを実行できます。

thFooFromDouble :: (Real a, Show a) => a -> Q Exp
thFooFromDouble x
        | 0 <= x && x <= 1 = return $ AppE (VarE 'unsafeFooFromDouble)
                                           (LitE (RationalL (toRational x)))
        | otherwise        = fail $ show x ++ " is not between 0 and 1"

そして、これが最後の関数の使い方です。

$(thFooFromDouble 0.3)

$(!の間にスペースを入れないでください。

于 2013-02-22T23:33:15.540 に答える