2012-04-18 33 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

相關問題