如何解决为什么类型构造函数不能在 haskell 的类型类定义中使用?
data LinkedList a = Empty | Cons a (LinkedList a) deriving (Eq,Show)
instance Foldable LinkedList where
foldMap _ Empty = mempty
foldMap f (a `Cons` ll) = LinkedList (f a) (foldMap f ll)
似乎 LinkedList 构造函数不在范围内?为什么?
编译错误:
Data constructor not in scope: LinkedList :: m -> m -> m
|
17 | foldMap f (a `Cons` ll) = LinkedList (f a) (foldMap f ll)
| ^^^^^^^^^^
我搜索了一个解决方案,似乎我应该使用 'mapped' 而不是构造函数。这是非常令人困惑的。我没有在任何地方定义任何 Monoid 类型类。
你能解释一下为什么是 mappened
而不是构造函数吗? Monoid
函数 mappened
和 mempty
在哪里定义?
编辑---------------------------------------------- -----------------------
当我从 mappened 改回来时犯了一个错误。抱歉,但正确的问题是:
instance Foldable LinkedList where
foldMap _ Empty = mempty
foldMap f (a `Cons` ll) = Cons (f a) (foldMap f ll)
编译器错误:
• Occurs check: cannot construct the infinite type:
m ~ LinkedList m
• In the second argument of ‘Cons’,namely ‘(foldMap f ll)’
|
17 | foldMap f (a `Cons` ll) = Cons (f a) (foldMap f ll)
|
^^^^^^^^^^^^
为什么不能递归使用foldMap?以及 Monoid 函数的定义位置。
解决方法
在
data LinkedList a = Empty | Cons a (LinkedList a)
你有
-
LinkedList
,它是一个 type 构造函数:它将一般的 typea
作为参数并返回类型 {{1 }}; -
LinkedList a
,它是一个 value 构造函数:它接受一个普通类型Cons
的 value 和一个 value 类型为a
。
另一方面,这里
LinkedList a
您将 foldMap f (a `Cons` ll) = LinkedList (f a) (foldMap f ll)
用作 value 构造函数,这是错误的。
编译器错误消息应包含足够的详细信息,以便您找出代码有什么问题:
• Occurs check: cannot construct the infinite type:
m ~ LinkedList m
• In the second argument of ‘Cons’,namely ‘(foldMap f ll)’
|
17 | foldMap f (a `Cons` ll) = Cons (f a) (foldMap f ll)
|
^^^^^^^^^^^^
忽略关于“发生检查”和“无限类型”的部分,我认为这可能看起来有点令人困惑,它抱怨 foldMap f ll
应该具有 m
类型,但它具有实际类型 { {1}},或者可能(事实证明)反过来。那么让我们自己看看类型。
它以 LinkedList m
的类型开头,我们可以在 documentation 中轻松找到:
foldMap
这意味着对于任何 Monoid foldMap :: Monoid m => (a -> m) -> t a -> m
(无论调用者选择哪个特定 Monoid 作为函数 foldMap f ll
的返回类型),m
都将具有类型 m
。
同时,f
的类型为 f
,因此 a -> m
的类型必须为 f a
- 同样对于 m
选择的任意 Monoid
实例.因此,当 f
用作 f a
- Cons
的第一个参数时 - 我们可以比较 Cons (f a) (foldMap f ll)
的定义,它来自类型定义:
Cons
这告诉我们,由于 data LinkedList a = Empty | Cons a (LinkedList a)
的类型为 f a
,因此 m
必须是 Cons (f a) (foldMap f ll)
类型的值。因此 LinkedList m
必须具有相同的类型。 (因为定义中的两个 foldMap f ll
类型都应用于同一类型 LinkedList
。)
这给了我们编译器报告的问题 - a
必须同时属于 foldMap f ll
类型和 m
类型。
(旁白:GHC 在这一点上实际上并没有放弃,它假设类型实际上彼此相等并查看导致的结果。但在这里它只会导致无限回归:相关的值必须具有类型LinkedList m
等于 m
等于 LinkedList m
等等。Haskell 在值定义中可以像这样无限回归,但不允许它用于类型 - 因此“不能构造无限类型".)
我们如何修复此错误并获得正确的 LinkedList (LinkedList m)
定义?您尝试将 foldMap
和 f a
结合起来计算 foldMap f ll
的想法绝对正确。对于 foldMap f (Cons a ll)
所针对的特定(任意)Monoid,这两个都是 m
类型。我们不一定将它们与“普通函数”结合起来,比如 f
,因为我们不知道 (+)
是什么类型 - 它不一定是数字类型,或者其他什么.但是我们知道的一件事是它是 Monoid 的一个实例 - 因此我们确实可以使用 m
方法 Monoid
组合任意两个这样的值。事实上,我们真的无能为力,因为我们一无所知关于这里的 mappend
类型除了它是 {{1} 的一个实例} - 因此有 m
(和 Monoid
)可用。
所以只有一种方法可以将这些值组合成正确的定义,即:
mappend :: m -> m -> m
右侧没有 mempty :: m
(或 foldMap f (Cons a ll) = mappend (f a) (foldMap f ll)
) - 如果这让您感到困惑,请考虑 Cons
将 Empty
作为 输入(在这种特殊情况下是 foldMap
参数),但它不输出 LinkedList
,而是在任意选择的 Monoid Cons a ll
中输出一个值。
我希望这会有所帮助,但如果您之前没有接触过 LinkedList
,可能会有点难以理解 - 特别是如果您在没有先了解 Monoids 的情况下就试图了解 m
.我强烈建议围绕这些主题进一步阅读,包括以出色的 Typeclassopedia 作为起点(在这种情况下,主要是关于 Monoid 和 Foldable 的部分)。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。