用Monads递归加入Promises有什么意义? [英] What are the implications of the recursive joining of Promises in terms of Monads?

查看:166
本文介绍了用Monads递归加入Promises有什么意义?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道JavaScript的承诺从技术上讲既不是函数,也不是哈斯克尔意义上的单子,因为(除其他外)它们包括


  • 一个绑定操作,当一个纯函数被传入时(并且因此具有不明确的类型),它将回落到 map / li>
  • Promise 构造函数和 resolve (aka 返回)递归地嵌套承诺



第一个问题很容易绕过,正确的类型 a - > Promise b



第二个问题显然违反了参数多态函数的参数特征,即不能构造 m (ma)结构。但是这种结构在承诺/异步计算中意味着什么?对于 Promise(Promise a),我无法想到有意义的语义,其中 Promise 是一个monad。那么我们失去了什么?递归连接的含义是什么?



假设我们非常务实(当我们编写Javascript时,这就是我们应该做的),我们不能声称一个 Promise 是Javascript中的monad,如果我们照顾边缘情况的话?

解决方案


第一个问题可以通过总是提供一个正确的类型 a - >答应a


或者不使用然后作为monad的绑定操作,但是一些类型正确的操作。 Creed 是一个功能强大的诺言库,提供 map chain 方法,它们实现了 Fantasy-land规范的代数类型。



第二个问题也可以绕过以相同的方法,不使用 resolve ,但完成,而方法的静态作为单位函数。


但是这个结构在承诺/异步计算环境中意味着什么?

这是对价值承诺的承诺。不是所有的可构造类型都需要有意义或有用: - )

然而,类似类型的一个很好的例子是由抓取API :它返回一个承诺,解析为响应对象,它再次包含解析为响应主体的承诺。

所以a Promise (Promise a)可能只有一个成功结果值,也可以通过 Promise a 来访问,但是两个承诺级别



  • 可能会在不同的时间完成,添加中间步骤可能会以不同的原因拒绝
  • 例如外部代表网络问题,内部代表解析问题



注意 Promise code> type应该有拒绝原因的第二个类型变量,类似于或者。两级 Promise err1(Promise err2 a) Promise err a 完全不同。


我知道JavaScript的承诺从技术上讲既不是哈斯克尔的意义上的函数也不是单子


然而,你还没有提到最大的问题:它们是可变的。如果我们考虑执行顺序,从待处理状态到稳定状态的转换是一种破坏参照透明度的副作用,当然,我们通常的承诺使用情况涉及许多非承诺类型模拟的IO。

  Promise.delay(50).then(()=> Promise.delay(50))
//做了一些不同的事情比
const a = Promise.delay(50); a.then(()=> a)

运用monad法则很有趣,但我们确实需要大量的实用主义。


I know that Javascript's promises are technically neither functors nor monads in the sense of Haskell, because (among other things)

  • they include a bind operation that falls back to map when a pure function is passed in (and thus has an ambiguous type)
  • both the Promise constructor and resolve (aka return) join nested promises recursively

The first issue can easily be bypassed by always providing a function with the right type a -> Promise b.

The second issue obviously violates the parametricity trait of parametric polymorphic functions, i.e. one cannot construct a m (m a) structure. But what would this structure mean in the context of promises/asynchronous computations? I cannot think of a meaningful semantics for Promise (Promise a), where Promise is a monad. So what do we lose? What are the implications of the recursive joining?

Provided we are pretty pragmatic (and that's what we should be when we're programming Javascript), can't we claim that a Promise is a monad in Javascript if we take care of the edge cases?

解决方案

The first issue can easily be bypassed by always providing a function with the right type a -> Promise a.

Or by not using then as the bind operation of the monad, but some type-correct ones. Creed is a functionally minded promise library that provides map and chain methods which implements the Fantasy-land spec for algebraic types.

The second issue can be bypassed as well with the same approach, by not using resolve but fulfill instead, and the static of method as the unit function.

But what would this structure mean in the context of promises/asynchronous computations?

It's a promise for a promise for a value. Not every constructible type needs to be "meaningful" or "useful" :-)

However, a good example of a similar type is provided by the Fetch API: it returns a promise that resolves to a Response object, which again "contains" a promise that resolves to the body of the response.

So a Promise (Promise a) might have only one success result value, which could as well be accessed through a Promise a, however the two levels of promises

  • might fulfill at different times, adding a "middle step"
  • might reject with different causes - e.g. the outer one representing a network problem while the inner one represents a parsing problem

Notice that the Promise type should have a second type variable for the rejection reason, similar to an Either. A two-level Promise err1 (Promise err2 a) is quite different from a Promise err a.

I know that Javascript's promises are technically neither functors nor monads in the sense of Haskell

You haven't mentioned the biggest issue yet, however: they're mutable. The transition from pending to settled state is a side effect that destroys referential transparency if we consider execution order, and of course our usual use cases for promises involve lots of IO that isn't modelled by the promise type at all.

Promise.delay(50).then(() => Promise.delay(50))
// does something different than
const a = Promise.delay(50); a.then(() => a)

Applying the monad laws is fun and occasionally useful, but we need lots of pragmatism indeed.

这篇关于用Monads递归加入Promises有什么意义?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆