DAY 22
0
Software Development

## Thunk

In computer programming, a thunk is a subroutine used to inject a calculation into another subroutine. Thunks are primarily used to delay a calculation until its result is needed, or to insert operations at the beginning or end of the other subroutine. They have many other applications in compiler code generation and modular programming. -wiki

``````thunk :: () -> a
``````

example

``````const secret = () => {
console.log('hi, :))))');
return 18;
}
``````

1. 改寫 `secret`， 從 impure 到 pure function
2. 用 secret number 繼續進行運算

``````const secretThunk = () => {
const secret = () => {
console.log('hi, :))))');
return 18;
}
return secret;
}
``````

``````secretThunk() // f
secretThunk() // f
secretThunk() // f
``````

``````const calcSecretNumber = (f) => {
return f() * 2;
}

calcSecretNumber(secret)

// hi, :))))
// 36
``````

``````const calcSecretNumberThunk = (f) => {
return () => f() * 2;;
}

const doubleSecret = calcSecretNumberThunk(secret)

``````

Constructor

``````IO :: () -> a
``````

Functor

``````const IO = run => ({
run,
map: (f) => IO(() => f(run()))
})

IO.of = (x) => IO(() => x);
``````

``````const secret = () => {
console.log('hi, :))))');
return 18;
};

const calcSecretNumber = (num) => num * 2;

const effect = IO(secret)
.map(calcSecretNumber)
.map(calcSecretNumber)

effect.run()
// hi, :))))
// 72
``````

Chain

``````const IO = run => ({
run,
map: (f) => IO(() => f(run())),
chain: (f) => IO(() => f(run()).run()),
})
``````

``````const otherEffect = (num) => IO.of(R.add(10, num));
``````

``````const effect = IO(secret)
.map(calcSecretNumber)
.map(calcSecretNumber)
.chain(otherEffect);

effect.run()

// hi, :))))
// 82
``````

Applicative Functor

``````const IO = run => ({
run,
map: (f) => IO(() => f(run())),
ap: eff => eff.map(effRun => effRun(run())),
chain: (f) => IO(() => f(run()).run()),
})

const lift2 = R.curry((g, f1, f2) => f2.ap(f1.map(g)))
``````

`ap` 也不用多加贅述，想必各位讀者都非常熟悉了! 也就是將兩個以上的 IO 跟函式進行結合!

``````const result = lift2(R.add, IO.of(1), IO.of(1))

result.run() // 2
``````

## point-free version

``````const of = a => () => a;
const map = (run) => (fb) => () => run(fb())
const chain = (run) => (mb) => () => run(mb())()
const ap = (run) => (f2) => () => {
const f = f2();
const a = run();
return f(a)
}
``````

example

``````const otherEffect = (num) => of(R.add(10, num));

const pipe = (init, ...fns) =>
fns.reduce((prevValue, fn) => fn(prevValue), init);

const effect = pipe(
secret,
map(calcSecretNumber),
map(calcSecretNumber),
chain(otherEffect)
);

effect();
// hi, :))))
// 82
``````