2012-12-31 30 views
6

我對Haskell來說很新,所以我希望這不是一個愚蠢的問題。我有這樣的數據類型:應用函數的參數可能是Ints或雙精度

data N = I Int | D Double deriving (Show, Eq) 

我想寫與該功能適用​​於數字的N秒鐘內,並返回結果的N簽名(Num a) => (a -> a -> a) -> N -> N -> N的功能。如果N s都是D s,則應該只應用該函數並返回D;如果一個人是一個I,另一個是D,它應該在IInt轉換爲Double,應用功能兩個Double S,並返回一個D;如果兩者都是I s,則應該應用該功能並返回I。這裏的(壞)的代碼,我到目前爲止有:

widen :: N -> N -> (N, N) 
widen (I i) [email protected](D _) = (D (fromIntegral i), d) 
widen [email protected](D _) [email protected](I _) = widen i d 
widen x y = (x, y) 

numOp :: (Num a) => (a -> a -> a) -> N -> N -> N 
numOp op x y = case widen x y of (D x', D y') -> D $ x' `op` y' 
           (I x', I y') -> I $ x' `op` y' 

我得到的numOp兩行的錯誤,雖然。第一個是:

Could not deduce (a ~ Double) 
from the context (Num a) 
    bound by the type signature for 
      numOp :: Num a => (a -> a -> a) -> N -> N -> N 
    at <line num> 
In the second argument of `($)', namely x' `op` y' 
In the expression: D $ x' `op` y' 
In a case alternative: (D x', D y') -> D $ x' `op` y' 

而第二個:

Couldn't match type `Double' with `Int' 
Expected type: Int 
    Actual type: a 
In the second argument of `($), namely x' `op` y' 
In the expression: I $ x' `op` y' 
In a case alternative: (I x', I y') -> I $ x' `op` y' 

我敢肯定,我明白這兩個錯誤的意思;我認爲第一個意思是說,我的類型簽名中的信息不足以讓GHC假定op返回D值構造函數所要求的Double,第二個說法是因爲第一行意味着aDouble,此行不能使用類型a的值,就好像它是Int。不過,我不知道從哪裏開始尋找正確的方法來做到這一點。

如果有幫助,我試圖得到這個工作的原因是,我跟着Write Yourself a Scheme tutorial;本教程中的所有示例(特別是在Evaluation section中)只涉及整數,但作爲練習,我希望增加支持整數和浮點數的功能,例如, (+ 1 2.5 2.5)返回6.0(+ 1 2 3)返回6。如果我想到這是錯誤的方式,或者有更簡單的方法來實現它,我很樂意聽到建議。

+0

不是一個愚蠢的問題。這個問題是一個相當不明顯的問題。 –

回答

7

簽名

numOp :: (Num a) => (a -> a -> a) -> N -> N -> N 

numOp需要a -> a -> a類型的任何單態功能的Num和兩個N小號每一個具體的實例,從計算的N。因此,例如,類型的函數

Complex Float -> Complex Float -> Complex Float 

approxRational :: RealFrac a => a -> a -> Rational 

(專門用於a = Rational)將是合法的第一個參數。

你需要的是一個多態函數,它可以處理所有的Num實例作爲第一個參數,即排名2型

numOp :: (forall a. Num a => a -> a -> a) -> N -> N -> N 

(您需要的RankNTypes語言擴展爲)。

+0

太棒了,非常感謝! – jcsmnt0

+1

如果您只處理rank-2類型,而不是較高等級的類型,則可以使用'Rank2Types'來代替。這有一個好處,它保留了可判定類型推斷(對於更高級類型而言失敗),儘管我從來沒有在實踐中看到過這種推理。 –

+1

你是否介意進一步解釋你的意思?我認爲保留可判斷類型推斷意味着我可以從我的'numOp'函數中移除顯式類型簽名,如果我有'Rank2Types'語言編譯指示,編譯器會成功推斷出它,但似乎並非如此。 – jcsmnt0

相關問題