我有这个相当简单的ADT:
data AST = Node String [AST]
| Leaf String
| Empty
deriving (Show)
和这个Functor实例:
instance Functor AST where
fmap f (Node s l) = Node (f s) (fmap f l)
fmap f (Leaf s) = Leaf (f s)
fmap f Empty = Empty
但是当我尝试编译它时,我得到了这个错误,我完全不明白:
Expected kind ‘* -> *’, but ‘AST’ has kind ‘*’
• In the first argument of ‘Functor’, namely ‘AST’
In the instance declaration for ‘Functor AST’
有谁知道为什么会这样?我无法在互联网上找到解决方案。
答案 0 :(得分:4)
仿函数适用于类型构造函数:如果你给它一个AST
,它希望看到:
data AST a = ...
-- ^ type parameter
我们也可以在Functor
类的定义中看到这一点:
class Functor (f :: * -> *) where
fmap :: (a -> b) -> f a -> f b
请注意,类头部的f
具有“ kind ”* -> *
这意味着它充当某种带有另一种类型的函数(第一个{ {1}})并生成一个类型(第二个*
)。正如您所看到的,*
将采用fmap
类型的函数(我们无法控制a -> b
是什么)。在您对b
的定义中,我们只能提供fmap
函数。
现在将String -> String
作为仿函数没有多大意义,因为它不是一个仿函数。
然而,您可以轻松将AST
概括为:
AST
如果您使用该类型,则data AST a = Node a [AST a]
| Leaf a
| Empty
deriving (Show)
等同于AST String
的旧定义。
同样适用于列表AST
(也是[]
)。列表的伪 - 定义是:
Functor
我们在列表中将data [] a = [] | a : [a]
定义为:
Functor
请注意我们不状态instance Functor [] where
fmap _ [] = []
fmap f (x:xs) = (f x) : (fmap f xs)
,但是Functor [a]
。
答案 1 :(得分:1)
Functors必须是多态的,即data AST a = ...
。在这种情况下,这就是“种类”的含义。它希望AST
不是一个类型,而是一个类型函数,它接受一个类型并返回一个类型。