自动强制数字类型

时间:2012-04-18 19:50:05

标签: haskell

我有一个类型

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 numeric tower

实际上我想要实现比我解释的更复杂的东西,因为我想要一些适用于任意数量的参数的东西,

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

将使用foldl1实现,但我觉得如果我能解决更简单的问题,那么我将能够解决这个更复杂的问题。

1 个答案:

答案 0 :(得分: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)
          ...

我认为你需要启用Rank2Types扩展(在源文件的顶部插入{-# LANGUAGE Rank2Types #-})来正确说明binaryOp的类型,我不确定我是否有语法正确......

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