2017-07-21 50 views
1

我有这个简单的ADT:自定义函子实例:期望一种 '* - > *',而是 'AST' 有种 '*'

data AST = Node String [AST] 
    | Leaf String 
    | Empty 
    deriving (Show) 

和函子实例:

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

作为一个健全性检查,这个实例'fmap'实际上做了什么吗? 'Functor'实例包含可以“映射”的事物,但AST中没有数据这样的可映射数据。 – jozefg

+2

应该注意的是,在这里'AST'和'fmap'定义构成了一个完全合理的分类仿函数,即使它们没有生成有效的Haskell'Functor'。 – pigworker

回答

4

仿函数适用于类型构造:如果你给它一个AST,它希望看到一个:

data AST a = ... 
--  ^type parameter

我们也可以看到这样的Functor类的定义

class Functor (f :: * -> *) where 
    fmap :: (a -> b) -> f a -> f b

请注意,f在班级的头部有“* -> *这意味着它作为某种功能需要另一种类型(第一个*)并生成一个类型(第二个*)。正如你可以看到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)。列表的 -definition是:

data [] a = [] | a : [a] 

我们定义Functor一个列表如下:我们做状态Functor [a],但Functor []

instance Functor [] where 
    fmap _ [] = [] 
    fmap f (x:xs) = (f x) : (fmap f xs)

心灵。

+0

小问题:我想知道“高阶类型”在这里是否合适。我认为,我以前从未遇到过这样的问题,并且我会将它与类似于(* - > *) - > *'的类似,与高阶函数类似。 be的'* - > *'类型是参数类型,参数化类型或(在正确的上下文中)类型族,类型函数。 – chi

+0

谢谢,我不知道Functor必须是多态的。对于我的代码,我只对String版感兴趣,所以我把它留了下来 – SuperManitu

1

函子必须是多态的,即data AST a = ...。在这种情况下,这就是“善良”的意思。它想要AST不是一个类型,而是一个类型函数,取一个类型并返回一个类型。

相关问题