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的一个很好的例子。我甚至不知道你可以在函数的域上进行存在的量化(虽然现在我已经看到了这一点,这似乎很明显…),所以我可能从来没有自己发现过这一点。