在从第一原理开始的Haskell编程部分中,给出了 Wrap 数据类型,以演示其Functor实例对其参数之一要求类型限制的类型:>
data Wrap f a =
Wrap (f a)
deriving (Eq, Show)
在为(包装f)演示了几个错误的Functor实例后,显示了正确的实例:
instance Functor f => Functor (Wrap f) where
fmap g (Wrap fa) = Wrap (fmap g fa)
这个类型类实例应该工作的事实在我看来是正确的。确实,GHC毫无保留地接受了它。
为了使自己确信需要'Functor f'约束,我尝试在没有该约束的情况下创建自己的类型类实例。我的方法着重于模式匹配,以在没有fmap的情况下以“ functor-ish”方式使用f,类似于本书前面所展示的方法。这是尝试:
instance Functor (Wrap f) where
fmap g (Wrap (f a)) = Wrap f (g a)
将其加载到GHCi中时,出现以下错误:
Prelude> :l 16.12-wrap.hs
[1 of 1] Compiling Main ( 16.12-wrap.hs, interpreted )
16.12-wrap.hs:10:17: error: Parse error in pattern: f
|
10 | fmap g (Wrap (f a)) = Wrap f (g a)
| ^^^
Failed, no modules loaded.
有人可以解释我尝试的实例的问题吗?在我看来,GHC有足够的信息可以从顶部的Wrap定义中推断出f是(*-> *)类型,所以我不明白为什么我的尝试无法解析。
答案 0 :(得分:3)
fmap g (Wrap (f a))
会导致分析错误,因为(f a)
不是语法有效的模式。
我的方法着重于模式匹配,以“ functor-ish”方式使用f而不使用fmap [...]
除了语法问题,您不能以这种方式从字面上使用f
作为模式。实例声明中的f
是类型构造函数,而模式则用于匹配值和值构造函数。为简单起见,请在...
id :: x -> x
id x = x
...类型签名中的x
(类型变量)与函数定义左侧的x
不同,该模式与值({{1 }})并将其绑定到变量(名为x
)。名称没有理由必须重合。
如果我能很好地理解您的意图,则计划使用x
作为一种模式,以使(f a)
与内部任何东西(f
)匹配的“ functor-ish”构造函数。那是行不通的(我们不能以这种方式对构造函数进行抽象),但是即使它以某种方式起作用了,也不能胜任这项任务。这是因为并非所有函数值都适合包装其他值的构造函数。一个示例:a
。这里没有一元值构造函数,也没有包装任何值。