试图将我的思想围绕遍历 - 或者在这种情况下可能略有不同。
我将遍历理解为对可遍历结构执行应用操作(或效果)的操作。因此,例如从Data.Traversable,
>>> mapM (\n -> [1..n]) $ Just 3
[Just 1,Just 2,Just 3]
wheremapM
只是traverse
for monads 的一种形式。所以这需要一个函数g
,它返回一个从 1 到函数输入的列表,以及一个Maybe
. 在 上遍历这个列表返回函数的结果Maybe Just
是Just
应用于列表中每个元素的构造函数,范围从 1 到3
原始 中包含的Just
。这一切都很好。
我想知道的是,如果我们稍微概括一下会怎样g
。在遍历中,g
获取a
与 中包含的类型匹配的类型值Traversable
,并返回结果类型的应用程序b
:
traverse :: Applicative f => (a -> f b) -> Const m a -> f (Const m b)
----------
相反,如果不是g
仅返回f b
,而是返回与f (Const m b)
整个操作返回的类型相同的类型,该怎么办 -
?traverse-like? :: Applicative f => (a -> f (Const m b)) -> Const m a -> f (Const m b)
--------------------
我的具体上下文是这样的 - 我正在一个应用程序中工作,该应用程序由一系列Maybe
具有异步效果的计算组成,这些操作本身异步返回Maybe
s。所以它看起来像
- 从一个开始
Maybe
m1
traverse-like
一个异步操作m1
- 如果
m1
是Nothing
,则计算短路,即traverse-like
返回m2 == Nothing
计算 - 如果
m1
是Just x
,执行可能返回async Nothing
或的异步效果async Just x
,sttraverse-like
返回m2 == Nothing
或Just async x
- 如果
traverse-like
一个异步操作m2
...
此操作的主要用途是将 a Maybe async Maybe
(通过遍历a -> async Maybe
操作获得)展平为 a Maybe async
。
整个世界对我来说都是新的(来自命令式背景),所以如果我什至没有正确考虑这一点,我深表歉意 - 但我希望上面的例子至少能清楚地说明我想要完成的事情。它似乎比单纯的遍历更通用,类似于 how bind
is more general than map
- 但我不知道实际调用的操作是什么,或者它是否在这个特定用例之外有意义。如果在函数式编程、Haskell 等方面有更多经验的人能够阐明这种操作的本质,我将不胜感激。