Haskell 数字类型的自动强制

Haskell 数字类型的自动强制,haskell,Haskell,我有一种 data Value = Int Integer | Float Double | Complex (Complex Double) | ... (other, non-numeric types) 具有关联错误类型 data ValueError = TypeMismatch Value | ... (other constructors) type ThrowsError = Either ValueError

我有一种

data Value = Int Integer
           | Float Double
           | Complex (Complex Double)
           | ... (other, non-numeric types)
具有关联错误类型

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

type ThrowsError = Either ValueError
我想在类型上实现泛型二进制操作,自动强制到继承权中的最高类型,并在其中一个操作数不是数字类型(即函数)时发出错误信号

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实现,但我觉得如果我能解决更简单的问题,那么我就能解决更复杂的问题。

类似这样的问题:

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)
          ...
我认为您需要启用Rank2Types扩展(在源文件的顶部插入
{-#LANGUAGE Rank2Types#-}
)来正确声明
二进制操作的类型,我不确定语法是否正确


binaryOp
的类型比您想象的要复杂,因为
binaryOp
在调用
op
时选择
a
是什么。你写的东西会让
binaryOp
的调用者选择
a
是什么,这不是你想要的。

谢谢,我现在有了一个基本版本!这是StackOverflow的一个很好的例子。我甚至不知道你可以在函数的域上进行存在的量化(虽然现在我已经看到了这一点,这似乎很明显…),所以我可能从来没有自己发现过这一点。