// @flow import type { HKT2 } from './HKT' import type { Tuple } from './Tuple' import type { Monoid } from './Monoid' import type { Monad } from './Monad' import { HKT } from './HKT' import * as tuple from './Tuple' /* Example import type { Writer } from '../Writer' import * as writer from '../Writer' const stringMonoid = { empty: () => '', concat: (a, b) => [a, b].filter(Boolean).join(',') } function logNumber(n: number): Writer { return writer.injWriter(n, 'Got number: ' + n) } function multWithLog(): Writer { const a = logNumber(3) const b = logNumber(5) const m = writer.monadWriter(stringMonoid) return m.chain(a => { return m.chain(b => m.of(a * b), b) }, a) } writer.runWriter(multWithLog()) // => [15, "Got number: 3, Got number: 5, "] */ class IsWriter {} export type WriterV = () => Tuple; export type Writer = HKT2; export function inj(a: WriterV): Writer { return ((a: any): Writer) } export function prj(fa: Writer): WriterV { return ((fa: any): WriterV) } export function runWriter(w: Writer): Tuple { return prj(w)() } export function evalWriter(w: Writer): A { return tuple.fst(runWriter(w)) } export function execWriter(w: Writer): W { return tuple.snd(runWriter(w)) } export function writer(t: Tuple): Writer { return inj(() => t) } export function injWriter(a: A, w: W): Writer { return writer(tuple.inj([a, w])) } export function tell(w: W): Writer { return inj(() => tuple.inj([undefined, w])) } // TODO: change to getMonad export function monadWriter(monoid: Monoid): Monad> { function map(f: (a: A) => B, fa: Writer): Writer { return inj(() => { const [a, w] = tuple.prj(runWriter(fa)) return tuple.inj([f(a), w]) }) } function ap(fab: Writer B>, fa: Writer): Writer { return chain((f) => map(f, fa), fab) // <= derived } function of(a: A): Writer { return inj(() => tuple.inj([a, monoid.empty()])) } function chain(f: (a: A) => Writer, fa: Writer): Writer { return inj(() => { const [a, w1] = tuple.prj(runWriter(fa)) const [b, w2] = tuple.prj(runWriter(f(a))) return tuple.inj([b, monoid.concat(w1, w2)]) }) } return { map, ap, of, chain } }