【发布时间】:2017-11-01 12:57:52
【问题描述】:
我目前正在研究结合 Javascript 中的 monad 的惰性求值以及哪些用例可能会从这些演变而来。所以我尝试实现一个惰性类型,它实现了 functor/monad 类型类。相应的构造函数意味着它的参数和结果是惰性的。这是我想出的:
// a lazy type
// (() -> a) -> () -> b
const Lazy = thunk => () => thunk();
// (b -> a -> b) -> b -> Lazy a -> b
Lazy.fold = f => acc => tx => f(acc) (tx());
// (a -> b) -> Lazy a -> Lazy b
Lazy.map = f => tx => Lazy(() => f(tx()));
// Lazy (a -> b) -> Lazy a -> Lazy b
Lazy.ap = tf => tx => Lazy(() => tf() (tx()));
Lazy.of = Lazy;
// Lazy (Lazy a) -> Lazy a
Lazy.join = ttx => ttx();
// (a -> Lazy b) -> Lazy a -> Lazy b
Lazy.chain = ft => tx => Lazy.join(Lazy.map(ft) (tx));
// recursive bind (or chain in Javascript)
// Number -> (a -> b) -> a -> Lazy b
const repeat = n => f => x => {
const aux = m => y => m === 0
? Lazy(() => y)
: Lazy.chain(aux(m - 1)) (Lazy(() => f(y)));
return aux(n) (x);
};
// impure function to observe the computation
const inc = x => (console.log(++x), x);
// and run
console.log(repeat(5) (inc) (0)); // logs 1, 2, 3, 4, 5, () => thunk()
现在这显然没有意义,因为动作序列根本不是惰性的。 Lazy.join 只是过早地触发了评估。因此,出现了以下问题:
- Haskell 中的一元动作序列是否总是急切地评估?
- 惰性求值是一种无法由严格求值语言中的 monad 实现的效果吗?
我什至不确定我的研究是否有意义,所以请随意投票以结束这个问题。
【问题讨论】:
-
我想对所有这些速记变量名进行一些解释
-
join应该是tx => Lazy(tx()) -
@evolutionxbox
tx= 花式类型,ft= 返回花式类型的函数,花式类型 = 表示具有值的上下文的类型(Lazy的上下文是惰性求值和 thunk 分别。() -> a是 thunk 的签名,至少在 Javascript 中) -
我不知道这是否有帮助,但我喜欢从“相反”的角度思考你的情况。不是“单子可以实现惰性吗?”但是“我制作的这种 thunk 类型是单子的懒惰模型吗?/它有什么代数结构?”从类型开始,然后发现结构。
-
@luqui 这种隐性知识通常很有帮助,谢谢。我想我犯了一个常见的错误(新手),试图将每个效果包装到一个单子中。
标签: javascript haskell functional-programming lazy-evaluation