gpt4 book ai didi

haskell - 理解 Haskell 中的箭头

转载 作者:行者123 更新时间:2023-12-03 05:54:53 28 4
gpt4 key购买 nike

我一直在努力掌握箭头,因为它们是大多数 FRP 的基础实现。我想我理解基本思想 - 它们与 monad 相关,但在每个绑定(bind)运算符处存储静态信息,因此您可以遍历箭头链并查看静态信息,而无需评估整个箭头。

但是当我们开始讨论第一、第二和交换时我就迷失了。 2元组与箭头有什么关系?教程展示了元组的内容,就好像它是明显的下一步一样,但我并没有真正看到其中的联系。

就此而言,箭头语法直观上意味着什么?

最佳答案

请查看http://www.cs.yale.edu/homes/hudak/CS429F04/AFPLectureNotes.pdf ,这解释了箭头在 FRP 中的工作原理。

2 元组用于定义箭头,因为需要它来表示带有 2 个参数的箭头函数。

在 FRP 中,常量和变量通常表示为忽略其“输入”的箭头,例如

twelve, eleven :: Arrow f => f p Int
twelve = arr (const 12)
eleven = arr (const 11)

然后将函数应用程序转换为组合 (>>>):

# (6-) 12

arr (6-) <<< twelve

现在我们如何将 2 参数函数变成箭头?例如

(+) :: Num a => a -> a -> a

由于柯里化(Currying),我们可以将其视为返回函数的函数。所以

arr (+) :: (Arrow f, Num a) => f a (a -> a)

现在让我们将它应用到一个常量

arr (+)             -- # f     a (a -> a)
<<< twelve -- # f b Int
:: f b (Int -> Int)

+----------+ +-----+ +--------------+
| const 12 |----> | (+) | == | const (+ 12) |
+----------+ +-----+ +--------------+

嘿等等,这不起作用。结果仍然是一个返回函数的箭头,但我们期望类似于 f Int Int 的东西。 我们注意到 Arrow 中的柯里化(Currying)失败,因为只允许组合。因此我们必须首先对函数进行柯里化(Currying)

uncurry :: (a -> b -> c) -> ((a, b) -> c)

uncurry (+) :: Num a => (a, a) -> a

然后我们就有了箭头

(arr.uncurry) (+) :: (Num a, Arrow f) => f (a, a) a

二元组因此而产生。然后需要像 &&& 这样的一堆函数来处理这些二元组。

(&&&) :: f a b -> f a d -> f a (b, d)

然后就可以正确进行添加了。

(arr.uncurry) (+)        -- # f   (a,    a) a
<<< twelve -- # f b Int
&&& eleven -- # f b Int
:: f b a

+--------+
|const 12|-----.
+--------+ | +-----+ +----------+
&&&====> | (+) | == | const 23 |
+--------+ | +-----+ +----------+
|const 11|-----'
+--------+

(现在,对于具有 3 个参数的函数,为什么我们不需要像 &&&& 这样的三元组?因为 ((a,b),c)可以替代使用。)

<小时/>

编辑:来自 John Hughes 的原始论文将 Monads 概括为箭头,其原因如下

4.1 Arrows and Pairs

However, even though in case of monads the operators return and >>= are all we need to begin writing useful code, for arrows the analogous operators arr and >>> are not sufficient. Even the simple monadic addition function that we saw earlier

   add :: Monad m => m Int -> m Int -> m Int
add x y = x >>= \u -> (y >>= \v -> return (u + v))

cannot yet be expressed in an arrow form. Making dependence on an input explicit, we see that an analogous definition should take the form

   add :: Arrow a => a b Int -> a b Int -> a b Int
add f g = ...

where we must combine f and g in sequence. The only sequencing operator available is >>>, but f and g do not have the right types to be composed. Indeed, the add function needs to save the input of type b across the computation of f, so as to be able to supply the same input to g. Likewise the result of f must be saved across the computation of g, so that the two results can eventually be added together and returned. The arrow combinators so far introduced give us no way to save a value across another computation, and so we have no alternative but to introduce another combinator.

关于haskell - 理解 Haskell 中的箭头,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3154701/

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