在Haskell Programming From First Principles部分16.13中,Wrap数据类型用于演示一种类型,其Functor实例需要对其中一个参数进行类型类约束:
data Wrap f a =
Wrap (f a)
deriving (Eq, Show)
演示了几个不正确的Functor for(Wrap f)实例后,会显示一个正确的实例:
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有足够的信息来推断f在顶部的Wrap定义中的类型(* - > *),所以我无法理解为什么我的尝试不解析。
定义左侧的fmap g (Wrap (f a))
导致解析错误,因为(f a)
不是语法上有效的模式。
我的方法专注于模式匹配,以“没有fmap [...]的”functor-ish“方式使用f
除了语法问题,你不能以这种方式将f
用作模式。实例声明中的f
是一个类型构造函数,而模式则用于匹配值和值构造函数。最简单的插图,...
id :: x -> x
id x = x
...来自类型签名的x
,一个类型变量,与函数定义左侧不同的x
,一个匹配值(类型为x
)并将它们绑定到变量(名为x
)的模式。名称必须重合,没有理由。
如果我理解你的意图,计划是使用(f a)
作为一种模式,使f
匹配任何“functor-ish”构造函数与内部的某些东西(a
)。这不起作用(我们不能以这种方式抽象构造函数),但即使它以某种方式工作,它也不足以完成这项任务。那是因为并非所有的函数值都适合包含其他值的构造函数的模型。一个例子:Nothing :: Maybe Integer
。这里没有一元值构造函数,也没有包装任何值。