1

私はタイプを持っています

data Value = Int Integer
           | Float Double
           | Complex (Complex Double)
           | ... (other, non-numeric types)

関連するエラータイプ

data ValueError = TypeMismatch Value | ... (other constructors)

type ThrowsError = Either ValueError

階層内の最上位の型への自動強制と、オペランドの1つが数値型でない場合のエラーシグナリング、つまり関数を使用して、型に対してジェネリック二項演算を実装したいと思います。

binaryOp :: Num a => (a -> a -> a) -> Value -> Value -> ThrowsError Value 

たとえば、私が書くことができるように

(binaryOp (+)) (Int 1) (Int 1)      ==> Right (Int 2)
(binaryOp (+)) (Int 1) (Float 1.0)  ==> Right (Float 2.0)
(binaryOp (+)) (Int 1) (String "1") ==> Left (TypeMismatch (String "1"))

これを行う簡単な方法はありますか?私の最初の考えは、次のようなものを定義することでした

data NumType = IntType | FloatType | ComplexType

機能と一緒に

typeOf :: Value -> NumType
typeOf (Int _) = IntType
...

promote :: Value -> Value
promote (Int n)   = Float (fromInteger n)
promote (Float n) = Complex (n :+ 0)

しかし、私はそれを機能させるのに苦労しています。何かアドバイス?


もう少しコンテキスト。私はSchemeインタープリターを書いていますが、Scheme数値タワーを実装したいと思います。

実際、私は説明したものよりも少し複雑なことを達成したいと思っています。なぜなら、次の行に沿って、任意の数の引数に適用できるものが必要だからです。

binaryOp :: Num a => (a -> a -> a) -> [Value] -> ThrowsError Value

これはで実装されますがfoldl1、もっと単純な問題を解決できれば、このもっと複雑な問題も解決できると思います。

4

1 に答える 1

2

このようなもの:

data NumType = IntType | FloatType | ComplexType | NotANumType
  deriving (Eq, Ord)

binaryOp :: (forall a. Num a => a -> a -> a) -> Number -> Number -> ThrowsError Number
binaryOp op x y
   = case typeOf x `max` typeOf y of
          ComplexType -> Complex (asComplex x `op` asComplex y)
          ...

{-# LANGUAGE Rank2Types #-}のタイプを正しく指定するには、Rank2Types拡張子(ソースファイルの先頭に挿入)を有効にする必要があると思いますがbinaryOp、構文が正しいかどうかはわかりません...

のタイプは、呼び出すときに何を選択するかを選択するbinaryOpため、思ったよりも複雑です。あなたが書いたものは、あなたが望むものではないものを、発信者が選択することになるでしょう。binaryOpaopbinaryOpa

于 2012-04-18T20:10:23.067 に答える