Skip to content

Instantly share code, notes, and snippets.

@DrBoolean
Last active June 10, 2016 01:12
Show Gist options
  • Save DrBoolean/da8a21e2058359f6c332 to your computer and use it in GitHub Desktop.
Save DrBoolean/da8a21e2058359f6c332 to your computer and use it in GitHub Desktop.
monads in a minute
[1,2,3].map(x => x+1)
// [2, 3, 4]
[1,2,3].map(x => [x+1])
// [[2], [3], [4]]
[1,2,3].chain(x => [x+1])
// [2, 3, 4]
[1,[2],3].chain(x => [x+1])
// [2, [3], 4]
var users = [{friends: ['sara', 'ajit']}, {friends: ['ross']}]
users.map(x => x.friends)
// [["sara", "ajit"], ["ross"]]
users.chain(x => x.friends)
// ["sara", "ajit", "ross"]
// assumes [].prototype has been extended with chain.
Promise.of(2).map(x => x + 1)
// Promise(3)
Promise.of(2).chain(x => Promise.of(x + 1))
// Promise(3)
Promise.of(2).chain(x => Promise.of(Promise.of(x + 1)))
// Promise(Promise(3))
http.get('/current_user').map(u => http.get('/todos', {user_id: u.id}))
// promise of promise of todos
http.get('/current_user').chain(u => http.get('/todos', {user_id: u.id}))
// promise of todos
Maybe.of(1).map(x => x+1)
// Just(2)
Maybe.of(null).map(x => x+1).map(x => x / 2)
// Nothing
Maybe.of(1).map(x => Maybe.of(x+1))
// Just(Just(2))
Maybe.of(1).chain(x => Maybe.of(x+1))
// Just(2)
Maybe.of(null).chain(x => Maybe.of(x+1))
// Nothing
getProp('user', {user: {name: 'bob'}}).map(u => getProp('name', u)).map(n => n.toUpperCase())
// Just(Just('BOB'))
getProp('user', {user: {name: 'bob'}}).chain(u => getProp('name', u)).map(n => n.toUpperCase())
// Just('BOB')
getProp('user', {}).chain(u => getProp('name', u)).map(n => n.toUpperCase())
// Nothing
EventStream.of("hello").map(x => x + " world")
EventStream.of("hello").chain(x => EventStream.of(x + " world"))
("input").keyDown().map(e => e.target.value)
// stream of values
("input").keyDown().map(e => search(e.target.value))
// stream of stream of search results
("input").keyDown().chain(e => search(e.target.value))
// stream of search results
@DrBoolean
Copy link
Author

chain is also called flatMap which makes more sense. It's also called bind / >>=.
of is called unit. It just puts anything in the type regardless of what the constructor wants.

@DrBoolean
Copy link
Author

oh yeah.

const getProp = (key, obj) => Maybe.fromNullable(obj[key])

@DrBoolean
Copy link
Author

@mpj
Copy link

mpj commented Feb 24, 2016

@DrBoolen "Monads in a minute" love it. What is "user" on line 14?

@mpj
Copy link

mpj commented Feb 24, 2016

My brain is slowly wrapping itself around this concept now.
The Maybe monad disturbs me a bit though - on line 37 and line 40, the map can return either a Just or a Nothing, but dealing with the array functor, we've learned that map must preserve is it's type and size. Why doesn't the maybe monad seem to obey this same restriction? Is it because it's sort of an enum-like thing in Haskell?

@DrBoolean
Copy link
Author

@mpj I updated user to be more correct and self explanatory.

Good eye on the Maybe. It is indeed an enum or "sum type". Which means it can be Just | Nothing and it still holds its structure. Kind of like a List of Cons|Nil.

I usually use a simplified version for teaching which looks something like:

const Maybe = x => ({
  map: f => Maybe(x ? f(x) : x),
  chain: f => x ? f(x) : Maybe(x),
})

The reason the simplified version is a little incorrect is that we should never be inspecting the value of x within map/chain - it should just mechanically apply in an expected way. Inspection of x breaks parametric polymorphism or universal qualification of the value inside of a functor.

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