Skip to content

Instantly share code, notes, and snippets.

@gcanti
Last active December 1, 2020 08:04
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gcanti/087a190fe0090210b82939f4bf3a1531 to your computer and use it in GitHub Desktop.
Save gcanti/087a190fe0090210b82939f4bf3a1531 to your computer and use it in GitHub Desktop.
Free Monad example, Flow and fp-ts, npm install fp-ts
// @flow
import type { Free } from 'fp-ts/lib/Free'
import { liftF } from 'fp-ts/lib/Free'
import { Identity, identity } from 'fp-ts/lib/Identity'
// Creating set of instructions (AST)
export class Write<A> {
+_tag: 'Write' = 'Write';
+message: string;
+more: A;
constructor(message: string, more: A) {
this.message = message
this.more = more
}
}
export class Read<A> {
+_tag: 'Read' = 'Read';
+more: (input: string) => A;
constructor(more: (input: string) => A) {
this.more = more
}
}
export type ConsoleT = <U, L, A>(x: [U, L, A]) => Console<A>
export type Console<A> = Write<A> | Read<A>
export type ConsoleF<A> = Free<ConsoleT, A>
// Creating the DSL
export const write = (message: string): ConsoleF<void> => liftF(new Write(message, undefined))
export const read = (): ConsoleF<string> => liftF(new Read(a => a))
// A program
const program = write("What's your name?")
.chain(() => read())
.chain(name => write(`Hello ${name}!`))
// Running the program
export function exaustive(x: empty): empty {
return x;
}
export function identityInterpreter<A>(fa: Console<A>): Identity<A> {
switch (fa._tag) {
case 'Write':
console.log(fa.message)
return identity.of(fa.more)
case 'Read':
return identity.of(fa.more('Giulio'))
}
return exaustive(fa)
}
program.foldFree(identity)(identityInterpreter)
/*
What's your name?
Hello Giulio!
*/
// Another Interpreter
import { IO, io } from 'fp-ts/lib/IO'
export const prompt: IO<string> = new IO(() => window.prompt(''))
export const log = (message: string): IO<void> => new IO(() => window.alert(message))
export function ioInterpreter<A>(fa: Console<A>): IO<A> {
switch (fa._tag) {
case 'Write':
const a = fa.more
return log(fa.message).map(() => a)
case 'Read':
return prompt.map(fa.more)
}
return exaustive(fa)
}
program.foldFree(io)(ioInterpreter).run()
/*
An alert, a prompt and another alert with the name you inserted will be displayed in the browser
*/
@civilizeddev
Copy link

WARNING: Deprecated

  • It looks like it does not work on the current version of fp-ts.
  • Free does not exist in fp-ts but in fp-ts-contrib now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment