Skip to content

Instantly share code, notes, and snippets.

@gcanti
Last active December 18, 2017 22:02
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gcanti/10c8e1b3bb4b759681f8014b4cd7f820 to your computer and use it in GitHub Desktop.
Save gcanti/10c8e1b3bb4b759681f8014b4cd7f820 to your computer and use it in GitHub Desktop.
MTL-style example, Flow and fp-ts, npm install fp-ts
// @flow
import type { Monad } from 'fp-ts/lib/Monad'
import type { HKT } from 'fp-ts/lib/HKT'
import { liftA2 } from 'fp-ts/lib/Apply'
import { flatten } from 'fp-ts/lib/Chain'
// Adapted from https://tech.iheart.com/why-fp-its-the-composition-f585d17b01d3
interface MonadUser<M> extends Monad<M> {
validateUser<U, L>(token: string): HKT<M, U, L, string>;
facebookToken<U, L>(uid: string): HKT<M, U, L, string>;
}
interface MonadFB<M> extends Monad<M> {
findPost<U, L>(url: string): HKT<M, U, L, string>;
sendLike<U, L>(fbToken: string): (post: string) => HKT<M, U, L, boolean>;
}
interface MonadApp<M> extends MonadUser<M>, MonadFB<M> {}
function likePost<M, U, L>(M_: MonadApp<M>): (token: string) => (url: string) => HKT<M, U, L, boolean> {
return token => url => {
const mToken = M_.chain(uid => M_.facebookToken(uid), M_.validateUser(token))
const mPost = M_.findPost(url)
const mmResult = liftA2(M_)(M_.sendLike)(mToken)(mPost)
return flatten(M_)(mmResult)
}
}
//
// IO
//
import { io, IO } from 'fp-ts/lib/IO'
import type { URIT as IOURIT } from 'fp-ts/lib/IO'
const validateUserIO = (token: string): IO<string> => io.of(`string(${token})`)
const facebookTokenIO = (uid: string): IO<string> => io.of(`FBToken(${uid})`)
const findPostIO = (url: string): IO<string> => io.of(`FBPost(${url})`)
const sendLikeIO = (fbToken: string) => (post: string): IO<boolean> => new IO(() => {
console.log(`sending like with fbToken "${fbToken}" and post "${post}"`)
return true
})
const monadAppIO: MonadApp<IOURIT> = {
map: io.map,
of: io.of,
ap: io.ap,
chain: io.chain,
validateUser: validateUserIO,
facebookToken: facebookTokenIO,
findPost: findPostIO,
sendLike: sendLikeIO
}
console.log(likePost(monadAppIO)('session123')('https://me.com/1').run())
// => sending like with fbToken "FBToken(string(session123))" and post "FBPost(https://me.com/1)"
// => true
//
// Task
//
import { Task, task } from 'fp-ts/lib/Task'
import type { URIT as TaskURIT } from 'fp-ts/lib/Task'
const now = Date.now()
function delay<A>(a: A): (n: number) => Task<A> {
return n => new Task(
() =>
new Promise(resolve => {
setTimeout(() => {
console.log(`${String(a)} after ${(Date.now() - now) / 1000}`)
resolve(a)
}, n)
})
)
}
const validateUserTask = (token: string): Task<string> => delay(`string(${token})`)(1000)
const facebookTokenTask = (uid: string): Task<string> => delay(`FBToken(${uid})`)(500)
const findPostTask = (url: string): Task<string> => delay(`FBPost(${url})`)(2000)
const sendLikeTask = (fbToken: string) => (post: string): Task<boolean> => {
console.log(`sending like with fbToken "${fbToken}" and post "${post}"`)
return delay(true)(1000)
}
const monadAppTask: MonadApp<TaskURIT> = {
map: task.map,
of: task.of,
ap: task.ap,
chain: task.chain,
validateUser: validateUserTask,
facebookToken: facebookTokenTask,
findPost: findPostTask,
sendLike: sendLikeTask
}
likePost(monadAppTask)('session123')('https://me.com/1')
.run()
.then(result => console.log(result))
// => string(session123) after 1.002
// => FBToken(string(session123)) after 1.503
// => FBPost(https://me.com/1) after 2.002
// => sending like with fbToken "FBToken(string(session123))" and post "FBPost(https://me.com/1)"
// => true after 3.004
// => true
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment