Javascript 从单子的角度来看,承诺的递归连接意味着什么?
我知道Javascript的承诺在技术上既不是Haskell意义上的函子也不是单子,因为(除其他外)Javascript 从单子的角度来看,承诺的递归连接意味着什么?,javascript,haskell,promise,monads,es6-promise,Javascript,Haskell,Promise,Monads,Es6 Promise,我知道Javascript的承诺在技术上既不是Haskell意义上的函子也不是单子,因为(除其他外) 它们包括一个bind操作,当传入纯函数时,该操作返回到map(因此具有不明确的类型) Promise构造函数和resolve(akareturn)递归地连接嵌套的承诺 通过始终提供类型正确的函数a->Promise b,可以轻松绕过第一个问题 第二个问题显然违反了参数多态函数的参数特性,即不能构造m(ma)结构。但是,在承诺/异步计算的上下文中,这种结构意味着什么?我想不出Promise(P
- 它们包括一个
操作,当传入纯函数时,该操作返回到bind
(因此具有不明确的类型)map
构造函数和Promise
(akaresolve
)递归地连接嵌套的承诺return
a->Promise b
,可以轻松绕过第一个问题
第二个问题显然违反了参数多态函数的参数特性,即不能构造m(ma)
结构。但是,在承诺/异步计算的上下文中,这种结构意味着什么?我想不出Promise(Promise a)
有什么意义的语义,其中Promise
是单子。那么我们会失去什么呢?递归连接的含义是什么
如果我们非常务实(这也是我们在编写Javascript时应该做到的),那么如果我们考虑到边缘情况,我们难道不能声称承诺是Javascript中的单子吗
通过始终提供类型正确的函数a->Promise a
,可以轻松绕过第一个问题
或者不使用then
作为monad的bind
操作,而是使用一些类型正确的操作。是一个功能性的promise库,提供了map
和chain
方法,这些方法实现了代数类型的
第二个问题也可以用相同的方法绕过,不使用resolve
,而是使用fulfill
,将
方法的静态作为单位函数
但是,在承诺/异步计算的上下文中,这种结构意味着什么
这是对价值的承诺。并非所有可构造类型都需要“有意义”或“有用”:-)
但是,类似类型的一个很好的例子是:它返回解析为响应的承诺
对象,该对象再次“包含”解析为响应主体的承诺
因此,Promise(Promise a)
可能只有一个成功结果值,也可以通过Promise a
访问该值,但是这两个级别的承诺
- 可能在不同的时间完成,添加“中间步骤”
- 可能会以不同的原因拒绝—例如,外部表示网络问题,而内部表示解析问题
请注意,Promise
类型应该有第二个类型变量作为拒绝原因,类似于或
。两级Promise err1(Promise err2 A)
与Promise err A
有很大不同
我知道Javascript的承诺在技术上既不是Haskell意义上的函子,也不是单子
然而,您还没有提到最大的问题:它们是可变的。当我们考虑执行顺序时,从未决状态到固定状态的转换是一个副作用,它破坏了参考透明性,当然,我们通常的承诺用例包含很多不被允诺类型所模拟的IO。
Promise.delay(50).then(() => Promise.delay(50))
// does something different than
const a = Promise.delay(50); a.then(() => a)
应用单子定律很有趣,偶尔也有用,但我们确实需要很多实用主义
我知道Javascript的承诺在技术上既不是Haskell意义上的函子,也不是单子
,以任何其他方式
- 它们包括一个绑定操作,当传入纯函数(因此具有不明确的类型)时,该操作返回到映射
JS native promises没有提供bind
操作符
- 承诺构造函数和resolve(aka return)都递归地连接嵌套承诺
我想你的意思是展开“thenables”,即调用存储在then
prop下的函数,只要有这样的函数
通过始终提供类型正确的函数a->Promise b
,可以轻松绕过第一个问题
这与map
不同,例如当map(f)
用于
f=x=>{then:a=>a}
第二个问题显然违反了参数多态函数的参数特性,即不能构造m(ma)
结构
的确如此
但是,在承诺/异步计算的上下文中,这种结构意味着什么?我想不出Promise(Promise a)
有什么意义的语义,其中Promise
是单子。那么我们会失去什么呢?递归连接的含义是什么
您需要允许存储任意值。承诺不允许存储不可拆封的信封,这就是问题所在。所以您需要更改对象和方法的语义。允许对象在不更改的情况下存储可伸缩性,并实现一次精确展开(或连接)可伸缩性的.bind
aka.chain
,无需递归
这就是promise类对象和基于回调(又名连续传递样式)函数的作用
如果我们非常务实(这也是我们在编写Javascript时应该做到的),那么如果我们考虑到边缘情况,我们难道不能声称承诺是Javascript中的单子吗
编写安全、简洁和可组合的代码是务实的。冒着通过泄漏的抽象引入细微缺陷的风险,可能会使关键软件崩溃并产生深远的后果,这是不可能的。
每个边缘案例都是此类风险的潜在来源
在这方面,声称Promise
是单子除了不正确之外,弊大于利。这是有害的,因为您无法安全地应用一元变换