[英]Haskell: Rigid type variable error when pattern matching bind operator
我正在嘗試運行
newtype Test a = Test (Int, a)
instance Monad Test where
Test (_, []) >>= k =
k []
Test (_, a) >>= k =
k a
return a =
Test (0, a)
我得到錯誤:
Couldn't match expected type `a' with actual type `[t0]'
`a' is a rigid type variable bound by
the type signature for >>= :: Test a -> (a -> Test b) -> Test b
at C:\Users\david.phillips\Documents\code\test.hs:4:5
In the pattern: []
In the pattern: (_, [])
In the pattern: Test (_, [])
當我嘗試使用case語句而不是>> =的2個版本時,出現類似的錯誤。
我對Haskell相當陌生,無法理解為什么這行不通。
編輯:對不起,這是一個不好的例子。 假設>> =的第一個定義給出了不同的輸出。
class Monad m where
(>>=) :: m a -> (a -> m b) -> m b
(>>) :: m a -> m b -> m b
return :: a -> m a
fail :: String -> m a
Monad
實例通過類型變量a
進行參數化。 實際上,您聲稱它不是,因為在該變量的位置,您在空列表構造函數[]
上匹配了模式,表示“ a是某物的列表”。 例如的類型。 可以使用明確的量化來寫bind:
(>>=) :: forall a. ma -> (a -> mb) -> mb
您的定義可能對所有a
無效。
除了Sarah的答案之外,您實際上可以省略特定的模式匹配,
Test (_, []) >>= f = f []
是相同的
Test (_, a) >>= f = f a
所以你真的可以這樣寫
Test (_, a) >>= f = f a
return a = (0, a)
現在請記住,除了具有正確的類型之外,我們還應該擁有
m >>= return = m
return a >>= f = f a
(a >>= b) >>= c = a >>= (\a' -> b a' >>= c)
不過這讓我擔心
m = Test (1, 'c')
m >>= return === return 'c' === (0, 'c') /== m
因此, return
不再是一種身份,您將違反第一單子法則。 解決這個問題意味着return
將必須保留元組的第一個元素,這是有問題的,因為我們實際上並沒有告訴它。
天真的,讓我們破壞函數返回的第一個元組元素。
Test (a, b) >>= f = Test (a, snd (f b))
現在
Test (1, 'c') >>= return == Test (1, snd (return 'c')) == Test (1, 'c')
但是我們仍然有麻煩
let f a = Test (1, a)
return a >>= f == Test (0, snd (f a)) == Test (0, a) /== f a
所以這里的竅門是做州立單子的工作
newtype Test a = Test{ unTest :: Int -> (Int, a) }
instance Monad Test where
return a = Test $ \i -> (i, a)
(Test m) >>= f = Test $ \i -> let (i', a) = m i
in unTest (f a) $ i'
確實滿足單子法則*。 幸運的是,這已經存在於Control.Monad.State
。
**模seq
擺脫第一個模式。 您正在嘗試為特定類型創建單獨的定義,但是您不能這樣做。 所有定義都必須針對所有類型a
。 如果你能違反的是,第一個模式是一樣的第二圖案,但有a
必然[]
所以只寫:
instance Monad Test where
Test (_, a) >>= k =
k a
return a =
Test (0, a)
Test (0, []) >>= k
將匹配>>=
模式,並變為k []
,與您不必要的第一個模式完全相同。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.