您不能將類型簽名應用於函數定義模式。這是編寫它的語法上正確的方法:
normalize :: (Modular s a, Integral a) => a -> M s a
normalize a = M (mod a (modulus (__ :: s))) :: M s a
但是,這不起作用。你真正想要的是在函數的類型簽名中引用類型變量s。這可以通過使用ScopedTypeVariables擴展,這需要明確的量化來實現:
normalize :: forall a s. (Modular s a, Integral a) => a -> M s a
normalize x = M (Mod x (modulus (__ :: s)))
作爲一個建議,以提高你的代碼,我建議使用標記庫:
import Data.Proxy
modulus :: (Modular s a) => Proxy s -> a
這可以讓你獲得沒有醜陋的佔位符底部。把它寫的另一種方法是:
modulus :: (Modular s a) => Tagged s a
這也給你一個很好的概念的好處:你現在有兩種類型,Mod
模塊化的價值觀和Tagged
其模量。你可以自己定義的類型,也給它一個更好的名字:
newtype Mod s a = Mod { residue :: a }
newtype Modulus s a = Modulus { modulus :: a }
這一切不談,如果你想實際使用此,我建議什麼ocharles說:使用reflection庫。
聰明的方式來寫它,雖然爲了清晰起見,我更喜歡明確的類型簽名。我也建議翻轉'Mod'類型。 – ertes 2013-02-09 20:46:53
這是edwardk的方法。我想要避免'ScopedTypeVariables'。 – 2013-02-09 20:48:12