2012-04-18 38 views
1

我有一个类型数值类型

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")) 

有没有一种简单的方法来做到这一点?我首先想到的是与功能

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

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

沿定义类似

data NumType = IntType | FloatType | ComplexType 

,但我有困难,使其工作。有什么建议?


更多的上下文。我正在写一位计划翻译,我想实施计划numeric tower

其实我是想实现的东西稍微比我解释更复杂,因为我希望适用于参数任意数量的东西,沿着这将与foldl1实施的

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

线,但我觉得如果我能解决更简单的问题,那么我就能解决这个更复杂的问题。

回答

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,这不是你想要的。

+0

谢谢,我现在有一个基本的版本!这是StackOverflow最棒的例子。我甚至不知道你可以对函数的域进行存在量化(尽管现在我看到它似乎很明显......),所以我可能永远都不会自己发现它。 – 2012-04-18 20:35:33

相关问题