Skip to content

Instantly share code, notes, and snippets.

@arosien
Created August 6, 2012 04:40
Show Gist options
  • Save arosien/3270530 to your computer and use it in GitHub Desktop.
Save arosien/3270530 to your computer and use it in GitHub Desktop.
monads
Monad | effect | sequences the effect as | M[A] | bind: M[A] => (f: A => M[B]) => M[B]
Identity | nothing | continue | Id[A] | f(a)
Option | zero or one value (anonymous exception) | halt if None | Option[A] | if Some(a) f(a)
Either | exception with error type or one value | halt if Left | Either[L, A] | if Right(a) f(a)
List | any # of values (non-determinism) | halt if empty | List[A] | join(each f(a))
Reader | an environment; dependency-injection | function composition | R => A | (r: R) => f(a(r))
Writer | logging | append log value W | Writer[W, A](log: W, value: A) | k = f(a.value); Writer(a.log |+| k.log, k.value)
State | state | new state from old | State[S, A](s: S => (S, A)) |
Responder | continuation-passing
IO | side-effects
monads: trivial sequence -> for-comprehension -> add monads, and hence semantics, without changing the program
* "a monadic function is just a pure function from input values to output computations"
* "Monads turn control flow into data flow, where it can be constrained by the type system." — Oleg Kiselyov
* "From the perspective of Haskell, a monad is a mechanism that supports eff ectful computations. A monadic program is an arrow of type A → MB, where the monad is wrapped around the target. The operations that come with a monad organise eff ects: the unit  (also called "return") creates a pure computation, the multiplication  (also called "join") merges two layers of e ffects." - Ralf Hinze
# Email thread in #scala-functional
I find that people understand Functor/map() just fine, but when you jump to Monad/flatMap() (roughly-speaking) nobody really understands the consequence of flatMap(). But if you show examples using for-comprehensions then it is much clearer.
(Using flatMap() directly is usually a bad code smell in "general" code, IMHO)
I really like Tony's exposition of Monads, using a for-comprehension, where the comprehension structure *stays the same* while you *vary the monads used there*, e.g.,
```scala
// Example 1: Identity monad
val fm: Identity[Foo]
val bm: Identity[Bar]
for {
foo <- fm
bar <- bm
} yield foo.doStuff(bar)
```
Now if you change from Identity to Option:
```scala
// Example 2: Option monad
val fm: Option[Foo]
val bm: Option[Bar]
```
the for-comprehension *doesn't need to change*, but *the semantics have changed*.
In other words, you can add *effects* (exception handling via Option/Either, side-effects via IO, etc.) via (monadic) types, rather than you needing to "rewrite" your sequence into some other kind of structure.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment