第一所有,您收到的錯誤是種錯誤。一種是一種類型的「類型」。就像類型對值進行分類一樣,種類也對類型進行分類。正如Haskell從值推斷類型,它也從類型推斷類型。我們使用相同的符號::
來表示值具有某種類型(例如,1 :: Int
)並且表示類型具有某種類型(例如,Int :: *
)。
有在錯誤消息中提到兩種:*
是那種由值居住類型,如Int
和Bool
,而* -> *
是那種類型的構造如Maybe
,[]
,和IO
。您可以將類型構造函數看作類型級函數:Maybe
將類型(類型爲*
)作爲參數,並返回一個類型(也是類型*
),例如Maybe Int :: *
。種類以功能相同的方式進行咖喱;例如,Either
有那種* -> * -> *
,因爲它需要的那種*
兩個參數產生一類的一種*
:
Either :: * -> * -> *
Either Int :: * -> *
Either Int Bool :: *
所以誤差來源於類型類的約束你的Show
實例:
instance (Show m, Show r) => Show (Thread m r) where
------
Show
是可顯示的種類*
的類別。您可以通過鍵入GHCI :kind Show
(或:k Show
)看到這一點:
> :kind Show
Show :: * -> Constraint
所以Show
需要一個類型的一種*
並返回一個類型類的約束。沒有涉及約束的太多細節,這意味着Show m
意味着m :: *
。但是,Thread
的定義將m
的參數傳遞給Atomic
構造函數的定義,該構造函數的類型爲m (Thread m r)
。看看那種Thread
:
> :kind Thread
Thread :: (* -> *) -> * -> *
這意味着,m :: * -> *
,因此不匹配。
下一個錯誤是在你的Show
實例的執行,即:
show (Atomic m x) = "Atomic " ++ show m ++ " " ++ show x
- ----------------
在這裏您提供匹配多個字段的模式,但Atomic
只有一個領域。你應該改變的執行情況如下:
show (Atomic m) = "Atomic " ++ show m
如果刪除Show m
約束,你會看到一個更有用的錯誤消息:
Could not deduce (Show (m (Thread m r)))
arising from a use of ‘show’
from the context (Show r)
bound by the instance declaration at …
In the second argument of ‘(++)’, namely ‘show m’
In the expression: "Atomic " ++ show m
In an equation for ‘show’: show (Atomic m) = "Atomic " ++ show m
這是說你想打電話show
在類型m (Thread m r)
的值上,但在上下文中沒有該限制。所以,你可以添加:
instance (Show (m (Thread m r)), Show r) => Show (Thread m r) where
---------------------
這不是「標準」哈斯克爾,所以GHC開始提示擴展,允許它:
Non type-variable argument in the constraint: Show (m a)
(Use FlexibleContexts to permit this)
In the context: (Show (m a), Show r)
While checking an instance declaration
In the instance declaration for ‘Show (Thread m r)’
讓我們嘗試加入-XFlexibleContexts
(在命令行上ghci … -XFlexibleContexts
,在與:set -XFlexibleContexts
的會話,或與{-# LANGUAGE FlexibleContexts #-}
的源文件),因爲它實際上是一個非常良性的擴展。現在,我們得到一個不同的錯誤:
Variable ‘a’ occurs more often than in the instance head
in the constraint: Show (m a)
(Use UndecidableInstances to permit this)
In the instance declaration for ‘Show (Thread m r)’
我們可以添加-XUndecidableInstances
- 所有這意味着,你正在寫一個類型級計算是GHC不能證明將暫停。有時候這是不可取的,但在這種情況下,這很好,因爲我們知道實例解析會找到可接受的Show
實例或失敗。現在,編譯器接受它,我們可以嘗試我們的Show
例如,假設有像m ~ []
和r ~ Int
簡單的東西:
> Atomic [Atomic [Return 1, Return 2]] :: Thread [] Int
Atomic [Atomic [Return 1,Return 2]]
但是請注意,當你設置m
到沒有按」一類的構造函數,這將無法正常工作噸有任何Show
情況下,如IO
:
> Atomic (return (Atomic (return (Return 1) >> return (Return 2)))) :: Thread IO Int
No instance for (Show (IO (Thread IO Int)))
arising from a use of ‘print’
In a stmt of an interactive GHCi command: print it
此外,您也可能會注意到你缺少一些括號中的Show
實例的結果:
> Atomic (Right (Atomic (Left "asdf"))) :: Thread (Either String) Int
Atomic Right Atomic Left "asdf"
這是一個簡單的解決方案,我會留給你。
這將使您的實例的Free
從文章數據類型,如Toy
上班,順便:
> Atomic (Free (Output "foo" (Pure (Return "bar"))))
Atomic (Free (Output "foo" (Pure Return ("bar"))))
'M'是*類型構造*像'IO'或'Maybe'。它不是一個完整的類型(比如'IO()'或'Maybe String')。但'm(Thread m r)'是一個完整的類型。 – immibis
此外,數據構造函數'Atomic'只需要一個參數,而不是兩個。 – immibis