简而言之,Reader Monad只是一个函数的包装器。通过计算隐式传递配置信息是很好的:
const ap = f => x => f(x);
const id = x => x;
const co = x => y => x;
const comp = f => g => x => f(g(x));
const Reader = ap(cons => f => {
const t = new cons();
t.run = x => f(x);
return t;
}) (function Reader() {});
Reader.map = f => tf => Reader(comp(f) (tf.run));
Reader.ap = af => ag => Reader(x => af.run(x) (ag.run(x)));
Reader.chain = mf => fm => Reader(x => fm(mf.run(x)).run(x));
Reader.of = f => Reader(co(f));
Reader.ask = () => Reader(id);
Reader.asks = f => Reader.chain(Reader.ask) (x => Reader.of(f(x)));
Reader.local = f => tf => Reader(comp(tf.run) (f));
const compM = tDict => fm => gm => x =>
tDict.chain(tDict.chain(tDict.of(x)) (gm)) (fm);
const foo = n => Reader(env => (console.log(env), n + 1)),
c = compM(Reader) (foo) (foo) (2);
console.log(
c.run("shared environment")
);

然而,我无法找到local
的好例子,我缺乏想象力如何使用它。我知道local
只是contramap
,但这并没有多大帮助。那么它的目的是什么?
答案 0 :(得分:0)
我理解
local
只是contramap
,但这并没有多大帮助。那么它的目的是什么?
好contramap
和map
一样重要 - 在the example Bergi linked(此处翻译成JS)中,local
允许影响之前的值 >下一位读者得到它
const calculateLength =
Reader.map (s => s.length) (Reader.ask ())
const calculateModifiedLength =
Reader.local (s => 'Prefix ' + s) (calculateLength)
console.log (calculateLength.run ('12345'))
// '12345'.length == 5
// => 5
console.log (calculateModifiedLength.run ('12345'))
// 'Prefix 12345'.length == 12
// => 12
这是你的读者monad,精心重新格式化。我包含了每个函数的演示,以便我们可以验证每个结果是否正确。谢谢你让我终于了解这个有趣的monad!
const Reader = f =>
({ run : x => f (x) })
Reader.of = x =>
Reader (() => x)
Reader.chain = f => m =>
Reader (x => f (m.run (x)) .run (x))
Reader.map = f => m =>
Reader (x => f (m.run (x)))
Reader.ap = f => m =>
Reader (x => f.run (x) (m.run (x)))
Reader.join = m =>
Reader (x => m.run (x) .run (x))
Reader.ask = () =>
Reader (identity)
Reader.local = f => m =>
Reader (x => m.run (f (x)))
const identity = x => x
const sq = x => x * x
const add = x => y => x + y
const calculateLength =
Reader.map (s => s.length) (Reader.ask ())
const calculateModifiedLength =
Reader.local (s => 'Prefix ' + s) (calculateLength)
console.log
( Reader.chain (x => Reader.of (x + 1)) (Reader (sq)) .run (4) // 17 sq (4) + 1
, Reader.chain (x => Reader (add (x))) (Reader (sq)) .run (4) // 20 sq (4) + 4
, Reader.map (sq) (Reader (sq)) .run (4) // 256 sq (sq (4))
, Reader.ap (Reader.of (sq)) (Reader.of (4)) .run () // 16 sq (4)
, Reader.ap (Reader (add)) (Reader (sq)) .run (4) // 20 sq (4) + 4
, Reader.join (Reader.of (Reader.of (4))) .run () // 4
, Reader.ask () .run (4) // 4
, calculateLength .run ('12345') // 5 '12345'.length
, calculateModifiedLength .run ('12345') // 12 'Prefix 12345'.length
)
这是类型签名,对于那些感兴趣的人
Reader :: (e -> a) -> Reader e a
Reader.of :: a -> Reader e a
Reader.chain :: (a -> Reader e b) -> Reader e a -> Reader e b
Reader.map :: (a -> b) -> Reader e a -> Reader e b
Reader.ap :: Reader e (a -> b) -> Reader e a -> Reader e b
Reader.join :: Reader e (Reader e a) -> Reader e a
Reader.ask :: () -> Reader a a
Reader.local :: (e -> e) -> Reader e a -> Reader e a