gpt4 book ai didi

haskell - Typeclassopedia中Applicative的构成规律

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

我正在阅读 Typeclassopedia我在 Applicatives 部分遇到了麻烦。我想我(有点)明白了,但我想看看我的理解是否正确。

在组合法出现之前,应用法则都是有意义的。我只是无法解析它的右侧:

u <*> (v <*> w) = pure (.) <*> u <*> v <*> w

因此,我启动了 GHCI 并进行了一些实验。

Prelude> pure (.) <*> Just (+1) <*> Just (+2) <*> Just 34
Just 37

所以这验证了规律,但是我还是没看懂。我尝试了一些变体,看看是否能获得一些见解:

Prelude> pure (.) <*> Just (+1) <*> Just (+2) <*> Just (+3) <*> Just 34

<interactive>:26:1: error:
* Non type-variable argument in the constraint: Num (b -> b)
(Use FlexibleContexts to permit this)
* When checking the inferred type
it :: forall b. (Num (b -> b), Num b) => Maybe b

那么,组合适用于两个功能而不适用于三个功能?我不明白为什么。

然后我验证了<*>对于一个简单的表达式,它的工作方式和我想象的一样:

Prelude> Just (+1) <*> Just 1
Just 2

但是,以下方法不起作用:

Prelude>  Just (+1) <*> Just (+2) <*> Just 34

<interactive>:15:2: error:
* Non type-variable argument in the constraint: Num (b -> b)
(Use FlexibleContexts to permit this)
* When checking the inferred type
it :: forall b. (Num (b -> b), Num b) => Maybe b

因此,应用与组合不同。我以为Just (+2) <*> Just 34会导致 Just 36Just (+1) <*> Just 36会导致 Just 37 .组合运算符,(.) , 是必需的,但它仅适用于两个功能。我只是不明白为什么需要它或它是如何工作的。

而且,为了向水中投入更多的污垢,我尝试了以下方法:

Prelude> Just (,) <*> Just 2

失败是因为没有 Show 的实例对于结果。所以我尝试了:

Prelude> :t Just (,) <*> Just 2
Just (,) <*> Just 2 :: Num a => Maybe (b -> (a, b))

这给了我一点洞察力。我需要传递第二个值才能获得 tuple回。我试过:

Prelude> Just (,) <*> Just 2 Just 34

但是那失败了,而且错误消息真的没有帮助我弄清楚错误在哪里。所以,看看上面代码的类型,我意识到它和我输入的是一样的 Just (2, ) (或类似的东西,无论如何)。所以,我尝试了:

Prelude> Just (,) <*> Just (2) <*> Just 34
Just (2,34)

我真的很惊讶这能奏效。但在这种惊讶中萌生了理解的萌芽(我认为)。

我回到了 (<*>) 的定义在 Typeclassopedia 中发现它被定义为 left associative。在此之前我什至没有考虑过关联性。所以上面的表达式实际上会这样计算:

Prelude> Just (,) <*> Just (2) <*> Just 34
-- Apply the 2 as the first parameter of (,) leaving a function
-- that takes the second parameter
Just (2,) <*> Just 34
-- Now apply the 34 as the parameter to the resulting function
Just (2,34)

如果这是正确的,那么有效的组合法的例子是这样计算的:

Prelude> pure (.) <*> Just (+1) <*> Just (+2) <*> Just 34
pure (+1 . ) <*> Just (+2) <*> Just 34
pure (+1 . +2) <*> Just 34
Just 37

这也解释了为什么三个函数不能这样组合:

Prelude> pure (.) <*> Just (+1) <*> Just (+2) <*> Just (+3) <*> Just 34
pure (+1 . ) <*> Just (+2) <*> Just (+3) <*> Just 34
pure (+1 . +2) <*> Just (+3) <*> Just 34

并且,此时我们有一个组合函数,需要一个 Num 的实例。类型类,而是向它传递一个失败的函数。

以类似的方式:

Prelude>  Just (+1) <*> Just (+2) <*> Just 34

失败因为<*>不是组合,正在尝试应用函数,(+2)到另一个函数,(+1) ,并遇到类型约束。

那么,我的直觉在这里是正确的吗?我终于明白了吗?还是我(有点)有根据的猜测仍然不对?

最佳答案

这只是一个没有正确应用替换规则的情况,并且忘记了括号在这些替换中的重要性(尽管其中一些可以稍后删除)。该规则应表示为

u <*> (v <*> w) == (pure (.) <*> u <*> v) <*> w

然后

Just (+1) <*> (Just (+2) <*> Just 34)
-- u = Just (+1)
-- v = Just (+2)
-- w = Just 34
=> (pure (.) <*> u <*> v) <*> w
=> (pure (.) <*> Just (+1) <*> Just (+2)) <*> Just 34

要在上面添加另一层,您必须使用另一个 pure (.):

Just (+3) <*> (Just (+1) <*> (Just (+2) <*> Just 34))
-- u = Just (+3)
-- v = Just (+1)
-- w = Just (+2) <*> Just 34
=> (pure (.) <*> u <*> v) <*> w
=> pure (.) <*> Just (+3) <*> Just (+1) <*> (Just (+2) <*> Just 34)

如果您想从第一阶段开始使用形式,您将拥有

Just (+3) <*> ((pure (.) <*> Just (+1) <*> Just (+2)) <*> Just 34)
-- u = Just (+3)
-- v = pure (.) <*> Just (+1) <*> Just (+2)
-- w = Just 34
=> (pure (.) <*> u <*> v) <*> w
=> pure (.) <*> Just (+3) <*> (pure (.) <*> Just (+1) <*> Just (+2)) <*> Just 34

恐怕这并没有人们希望的那么漂亮。

关于haskell - Typeclassopedia中Applicative的构成规律,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48796444/

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