就 Monad 而言,递归连接 Promise 的含义是什么? [英] What are the implications of the recursive joining of Promises in terms of Monads?

查看:32
本文介绍了就 Monad 而言,递归连接 Promise 的含义是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道 Javascript 的承诺在技术上既不是 Haskell 意义上的函子也不是 monad,因为(除其他外)

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

  • 它们包含一个 bind 操作,当传入纯函数(因此具有不明确的类型)时,该操作回退到 map
  • Promise 构造函数和 resolve(又名 return)都递归地连接嵌套的 Promise
  • 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

通过始终提供具有正确类型的函数,可以轻松绕过第一个问题 a ->承诺 b.

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

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

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?

假设我们非常务实(这就是我们在编写 Javascript 时应该做的),如果我们注意边缘,我们不能声称 Promise 是 Javascript 中的单子案例?

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?

推荐答案

通过始终提供具有正确类型的函数,可以轻松绕过第一个问题 a ->承诺一个.

或者不使用 then 作为 monad 的 bind 操作,而是使用一些类型正确的操作.Creed 是一个功能性的 promise 库,提供 map 方法,为代数类型实现 Fantasy-land 规范.

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.

第二个问题也可以用同样的方法绕过,不使用 resolve 而是使用 fulfill 和静态 of 方法作为单元函数.

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.

但是这种结构在 promises/异步计算的上下文中意味着什么?

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" :-)

然而,提供了一个很好的类似类型的例子获取 API:它返回一个解析为 Response 对象的承诺,该对象再次包含"解析为响应正文的承诺.

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.

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

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

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

注意 Promise 类型应该有第二个类型变量用于拒绝原因,类似于 Either.一个两级的Promise err1 (Promise err2 a)Promise err a 完全不同.

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.

我知道 Javascript 的 promise 在技术上既不是 Haskell 意义上的函子也不是 monad

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

然而,您还没有提到最大的问题:它们是可变的.如果我们考虑执行顺序,从待定状态到已解决状态的转换是一个副作用,它会破坏引用透明度,当然,我们通常的 Promise 用例涉及大量 IO,而这些 IO 根本不是由 Promise 类型建模的.

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.

这篇关于就 Monad 而言,递归连接 Promise 的含义是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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