鉴于:
Applicative m, Monad m => mf :: m (a -> b), ma :: m a
Run Code Online (Sandbox Code Playgroud)
它似乎被认为是一项法律:
mf <*> ma === do { f <- mf; a <- ma; return (f a) }
Run Code Online (Sandbox Code Playgroud)
或者更简洁:
(<*>) === ap
Run Code Online (Sandbox Code Playgroud)
说的文档Control.Applicative<*>是"顺序应用程序",这表明了这一点(<*>) = ap.这意味着<*>必须从左到右依次评估效果,以保持一致>>=...但这感觉不对.McBride和Paterson的原始论文似乎暗示从左到右的排序是任意的:
IO monad,实际上任何Monad,都可以通过取
pure=return和<*>=来实现ap.我们也可以使用它的变量ap以相反的顺序执行计算,但我们将在本文中保持从左到右的顺序.
因此,有两个合法的,非平凡的推导<*>来源于>>=并且return具有不同的行为.在某些情况下,既没有这两个推导是可取的.
例如,(<*>) === …
这是我的Task实现方式(即一种Promise但符合monad法律且可取消的方式)。它工作坚如磐石:
const Task = k =>
({runTask: (res, rej) => k(res, rej)});
const tAp = tf => tk =>
Task((res, rej) => tf.runTask(f => tk.runTask(x => res(f(x)), rej), rej));
const tOf = x => Task((res, rej) => res(x));
const tMap = f => tk =>
Task((res, rej) => tk.runTask(x => res(f(x)), rej));
const tChain = fm => mx =>
Task((res, rej) => mx.runTask(x => fm(x).runTask(res, rej), rej));
const log = x => console.log(x);
const elog = …Run Code Online (Sandbox Code Playgroud)javascript continuations functional-programming continuation-passing
ap没有文档说明的规范,请阅读并指出可能是的注释<*>,但这并不是出于实际原因:
ap :: (Monad m) => m (a -> b) -> m a -> m b
ap m1 m2 = do { x1 <- m1; x2 <- m2; return (x1 x2) }
-- Since many Applicative instances define (<*>) = ap, we
-- cannot define ap = (<*>)
Run Code Online (Sandbox Code Playgroud)
所以我承担ap的(<*>) = ap法律是简写“AP的右手边”,实际上法律表达之间的关系>>=,return以及<*>对不对?否则,法律将毫无意义。
我正在考虑上下文Validation,并且似乎没有合法的Monad实例是多么令人不满意。我也在考虑ApplicativeDo,以及这种转换如何使我们从Monad实例的实际效果中恢复Validation;我最常想做的是尽可能地累积错误,但在必要时仍然能够使用bind。实际上bindV,我们导出了几乎在所有地方都需要使用的功能,这很荒谬。我能想到的唯一的实际后果是,我们会根据所使用的合成类型(或程序在理论上如何通过重写规则来转换)来累积不同或更少的错误,尽管我不确定为什么应用合成会转换为单子)。
编辑:在相同法律的文档Monad …