首页 > 解决方案 > 编写 promise 和自定义 monad

问题描述

语境

我试图理解 monades 试图解决的问题,在尝试编写容器和承诺时我有点困惑。

例子

出于练习的目的,我将chainmonad 的方法修改为 a then,以便可以使用自定义容器编写 Promise:

const assert = require("assert");
const R = require("ramda");

const makeMonad = value => ({
  get: () => value,
  map: transform => makeMonad(transform(value)),
  then: createMonad => makeMonad(createMonad(value).get())
});

const asyncAdd2 = x => Promise.resolve(x + 2);

const composeP = R.composeWith((f, last) => last.then(f));
const asyncResult = composeP([asyncAdd2, makeMonad])(1);

asyncResult.then(x => assert.equal(x, 3));
console.log("Passed");

在此示例中,我抛出了一个错误,因为PromiseAPI 不拥有get函数。事实上,我需要get在我的自定义then函数中使用这个函数来实现可组合性。

因此,在应用程序执行结束时,根据我在composeWith调用中的参数顺序,我处于 ​​Promise 世界或自定义 monad 世界。

问题

感谢您的帮助,我希望我已经清楚了^^'

标签: javascriptfunctional-programming

解决方案


我试图理解 monades 试图解决的问题

查看此 repo https://github.com/dmitriz/functional-examples中的示例和参考资料可能会对您有所帮助

在尝试编写容器和承诺时,我有点困惑。

我想你知道Promise 不是 Monad

出于练习的目的,我已将我的 monad 的 chain 方法修改为 a then,以便我可以使用我的自定义容器编写 Promise

由于then方法违反一元法则,不适合安全合成。基本上每次你用函数组合时,你必须仔细检查所有可能的返回值是否是承诺,并确保组合总是正确解包。这基本上违背了 Monad 的观点,即允许您安全地进行创作而无需花费时间进行细节检查。如果利用 Monads 是您的目标,您可能更愿意从 to 切换thenchain

Creed是一个为 Promises 带来 FP 安全性的优秀库


  • 我现在想知道在我工作并尝试编写单子时是否必须举起一切(甚至是承诺?)?

您可能希望将所有 Promise 包装进去creed,然后以通常的方式使用提供的 monadic 方法。

  • 如果我使用 10 种不同的单子会有什么影响?我的意思是,根据顺序,我可能会改变我正在努力的世界,不是吗?

单子法则适用于固定的单子,即它们仅适用于ofandchain方法的固定实现。还chain期望正确的签名:

chain :: Monad m => m a ~> (a -> m b) -> m b

Decrypted:如果m是一个固定的 Monad,a并且b是任何类型,chain 方法要求它的参数是 type 的函数a → m b,并且m同一个 monad

换句话说

monad.chain(a => makeMonad(a))

假定功能makeMonad是制作相同的 monad。否则,无论何时使用,您都需要将结果包装到正确的 monadchain中。

为了使它与 Promise 一起安全工作,总是将它们包装到 Creed 中以保证使用相同的 monad,然后只在编写和依赖 monad 法则时使用map和。chain或自then担风险使用并担心细节:)

  • 这是创建 monades 创造者的共同点吗?我的意思是像我写的 makeMonad 一样创建 monade 定义

这仅在您开始具有实际价值时才有效,请参见此处:https ://github.com/dmitriz/functional-examples/blob/master/examples/16-monad.js

但是 Monad 的强大功能之一是处理您不能(或不想)直接访问的值,例如 IO Monad。在这些情况下,您只能使用提供的运算符来可能或可能无法创建 Monad。这说明了原生 JS 承诺的问题——你不能以任何方式将它们变成 Monad 而不改变它们的值。原生 JS 承诺总是会尝试解开“theneable”,因此不能将其存储为值,这使得任何组合通常都是不安全的。


推荐阅读