首页 > 解决方案 > 为什么 GHC 不解析 'data Wrap fa = Wrap (fa)' 的函子实例?

问题描述

Haskell Programming From First Principles第 16.13 节中,展示了Wrap数据类型以演示其 Functor 实例需要对其参数之一进行类型类约束的类型:

data Wrap f a =
  Wrap (f a)
  deriving (Eq, Show)

在为 (Wrap f) 演示了几个不正确的 Functor 实例之后,显示了一个正确的实例:

instance Functor f => Functor (Wrap f) where
  fmap g (Wrap fa) = Wrap (fmap g fa)

这个类型类实例应该可以工作的事实对我来说似乎是正确的。事实上,GHC 毫无怨言地接受了它。

为了说服自己需要“Functor f”约束,我尝试在没有它的情况下创建自己的类型类实例。我的方法侧重于模式匹配,在没有 fmap 的情况下以“仿函数”的方式使用 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 是一种 (* -> *),所以我不明白为什么我的尝试没有解析。

标签: haskelltypeclassfunctor

解决方案


fmap g (Wrap (f a))在定义的左侧会导致解析错误,因为(f a)它不是语法上有效的模式。

我的方法侧重于模式匹配,以在没有 fmap 的情况下以“仿函数”的方式使用 f [...]

撇开语法问题不谈,您不能f以这种方式将其用作模式。实例声明中的f是类型构造函数,而模式旨在匹配值和值构造函数。对于一个最小的说明,在...

id :: x -> x
id x = x

...x来自类型签名的类型变量x与函数定义的左侧不同,后者是匹配值(类型x)并将它们绑定到变量(命名x)的模式。没有理由名称必须一致。

如果我很好地理解了您的意图,那么计划是(f a)用作一种模式,以便f将任何“仿函数”构造函数与a内部的某些东西 (the) 匹配。这不起作用(我们不能以这种方式抽象构造函数),但即使它确实以某种方式起作用,它也不足以完成这项任务。这是因为并非所有的函数值都适合包装其他值的构造函数的模式。一个例子:Nothing :: Maybe Integer。这里没有一元值构造函数,也没有任何值被包装。


推荐阅读