gpt4 book ai didi

haskell - 无法构造无限类型

转载 作者:行者123 更新时间:2023-12-02 10:49:47 25 4
gpt4 key购买 nike

我想使用应用功能,并尝试如下:

*ReaderExercise Control.Applicative> (+4) <*> (+3)

然后收到以下错误消息:
<interactive>:51:11: error:
* Occurs check: cannot construct the infinite type: a ~ a -> b
Expected type: (a -> b) -> a
Actual type: a -> a
* In the second argument of `(<*>)', namely `(+ 3)'
In the expression: (+ 4) <*> (+ 3)
In an equation for `it': it = (+ 4) <*> (+ 3)
* Relevant bindings include
it :: (a -> b) -> b (bound at <interactive>:51:1)

我期望的是带有一个参数的返回函数。
无限类型是什么意思?

最佳答案

当Haskell确定类型变量(由程序员明确给出或由Haskell隐式引入)必须满足一个条件时,将提示错误“发生检查:无法构造[无限]类型”,该条件暗示需要按以下方式递归定义:本身会导致无限的“深度”类型(即类型变量在其自己的定义中“出现”)。

它通常是由于程序员错误输入或概念错误引起的,该错误与混淆程序中的两个不同“结构级别”有关。

举一个简单的例子,一个整数列表(类型[Int])是有效的Haskell类型,一个整数列表的列表([[Int]])或一个整数列表的列表([[[[[Int]]]]])也只有一个允许数量有限的列表级别。您不能一直拥有列表列表列表等等。这将是一个无限类型。如果Haskell认为您希望它构造这种类型,它将给您“出现检查”错误。

定义如下:

yuck (x:xs) = x == xs

正是由于这个原因而给出此错误。 Haskell从左侧知道 yuck接受了一些未知元素类型 a的列表,其中变量 xa类型的头部,变量 xs[a]类型的尾部。在RHS中,运算符 (==)强制 xxs具有相同的类型-换句话说,它暗示了约束 a ~ [a],其中代字号表示“类型相等”。没有任何有限类型(没有具有有限数量的列表级别的类型)具有此属性,只有无效的无限类型 [[[[...forever...]]]]才能允许您删除外部列表级别,并且仍然剩下相同的类型,因此会出现错误。

这里的问题是程序员混淆了两个层次的结构:列表 xs和元素 x

在您的特定示例中,错误的原因类似,但更难解释。运营商:
(<*>) :: (Applicative f) => f (a -> b) -> f a -> f b

进行两个具有不同基础类型的应用操作:左侧具有应用函子 f给出的类型,该类型应用于基础类型 a -> b;右侧的类型由应用到底层类型 f的相同应用函子 b给出。

您尚未告诉Haskell您打算使用哪个应用函子 f,因此Haskell尝试进行推断。因为LHS具有类型:
(+4) :: (Num n) => n -> n

Haskell尝试将 n -> n类型与 f (a -> b)匹配。使用 (->)类型运算符的前缀形式来写这些类型可能更清楚:Haskell尝试将 (->) n nf ((->) a b)匹配,其中 f是一个应用函子。

幸运的是,对于每种类型 (->) t,都有一个适用于 t的应用仿函数实例。因此,Haskell会将所需的应用函子设为 f = (->) n,并成功将 (->) n n = f nf ((->) a b)匹配。这意味着 n等于 ((->) a b)。然后,Haskell尝试匹配RHS上的类型,将 (->) n n = f n(->) n a = f a匹配。这行得通,并且意味着 n等于 a

现在我们有一个问题。 n同时等于 a -> b(来自LHS)和 a(来自RHS)。这意味着将创建一个无限函数类型,如下所示:
(((... forever ...)->b)->b)->b)->b

这是删除外部 ...->b并保留相同类型的唯一方法。这是不可能的无限类型,因此会出现错误。

潜在的问题是您犯了一个概念上的错误。鉴于您正在研究 ReaderExample,我认为您打算使用 (->) n应用函子实例,因此您和Haskell在这一点上是一致的。在这种情况下:
(+4) :: (Num n) -> n -> n

是一种读取器操作,它从读取器中读取一个数字并将其添加四个。类似地, (+3)是一种读取器操作,它从读取器读取一个数字并将其添加三个。

但是, (<*>)是一种运算符,它对从读取器读取的LHS采取读取器操作,以产生 函数(不是数字!),然后将其应用于使用RHS从读取器读取以产生s的结果。数。例如,如果您定义:
multiplyByReader :: (Num n) -> n -> n -> n
multiplyByReader readerNum input = readerNum * input

然后:
multiplyByReader <*> (+4)

或更简单的版本:
(*) <*> (+4)

会很有意义。预期的含义是:构造一个读取器 Action ,该 Action (1)使用LHS从读取器读取数字以创建一个乘以读取器的函数;然后(2)将此功能应用于将RHS应用于阅读器的结果编号。

如您所见,这相当于 \r -> r * (r + 4):
> ((*) <*> (+4)) 5   -- same a 5 * (5 + 4)
45
>

当您编写 (+3) <*> (+4)时,您要混合使用两种不同的结构级别:LHS读取器产生一个数字,但应该产生一个可以应用于数字的函数。

我最好的猜测是您想创建一个读取器 Action ,将 (+4)应用于读取器以获取数字,然后将 (+3)应用于该结果。在这种情况下, (+3)不是读取器 Action ;它只是您要应用于读取器操作 (+4)的结果的函数,它等效于读取器操作上的 fmap ping:
(+3) <$> (+4)

当然,您可以等效地直接将其编写为:
(+3) . (+4)

两者都是复合阅读器操作,在读取的数字上增加了七个:
> ((+3) <$> (+4)) 5
12
> ((+3) . (+4)) 5
12
>

关于haskell - 无法构造无限类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46172732/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com