* 的类型:
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
的定义中,它的 Atomic
构造函数将参数传递给 m
,它有一个类型为 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
这段话的意思是您试图在类型为“m (Thread m r)
”的值上调用show
,但您的上下文中没有这个约束。因此,您可以添加它:
instance (Show (m (Thread m r)), Show r) => Show (Thread m r) where
---------------------
这不是“标准”的Haskell,所以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"
这是一个简单的修复,我会留给你来完成。
这应该使你的实例能够使用文章中的Toy
数据类型,并通过Free
进行操作:
> Atomic (Free (Output "foo" (Pure (Return "bar"))))
Atomic (Free (Output "foo" (Pure Return ("bar"))))
m
是像IO
或Maybe
一样的 类型构造器。它不是一个完整的类型(像IO ()
或Maybe String
)。但是m (Thread m r)
是一个完整的类型。 - user253751Atomic
只接受一个参数,而不是两个。 - user253751