Skip to content

Instantly share code, notes, and snippets.

@expede
Last active May 20, 2020 15:54
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 expede/59b4e7e49fd394210ca5f31c7f00f382 to your computer and use it in GitHub Desktop.
Save expede/59b4e7e49fd394210ca5f31c7f00f382 to your computer and use it in GitHub Desktop.
Witchcraft Monadic Do Notation Primer
# ========
# NOTATION
# ========
# Control.Monad (Haskell) Bind
>>=
# Witchcraft.Chain.bind (Elixir)
>>>
# ==========
# DESUGARING
# ==========
monad [] do
a <- [1]
b <- [2]
return(a + b)
end
# Same as
[1] >>> fn a ->
[2] >>> fn b ->
Witchcraft.Applicative.pure([], a + b) # <~ This is return(a + b) in the context of []
end
end
# Same as
Witchcraft.Chain.bind([1], fn a ->
Witchcraft.Chain.bind([2], fn b ->
Witchcraft.Applicative.pure([], a + b)
end)
end)
# ==========
# LIST MONAD
# ==========
monad [] do
1
end
#=> 1
monad [] do
return 1
end
#=> [1]
monad [] do
a <- [1, 2]
return a
end
#=> [1, 2]
# Strictly speaking, you don't need `return` at all!
monad [] do
a <- [1, 2]
[a] # Same as `return` in `[]`
end
#=> [1, 2]
monad [] do
a <- [1, 2, 3]
b <- [10, 100]
return(a * b)
end
#=> [10, 100, 20, 200, 30, 300]
# NOTE: length 2 x 3 (every element of `a` multiplied by every element of `b`)
monad [] do
a <- [1, 2, 3]
b <- [10, 100]
c <- return(a * b) # NOTE bind intermediate result to `c`
d <- [2, 4]
return(c + d)
end
#=> [20, 40, 200, 400, 40, 80, 400, 800, 60, 120, 600, 1200]
monad [] do
a <- [1, 2, 3]
b <- [10, 100]
c <- return(a * b)
return(a + b + c) # NOTE reusing `a` and `b`
end
#=> [21, 201, 32, 302, 43, 403]
# ===========
# MAYBE MONAD
# ===========
# @type Maybe.t :: %Just{just: any} | %Nothing{}
monad %Maybe.Just{} do
a <- %Just{just: 2}
b <- %Just{just: 10}
return(a * b)
end
#=> %Just{just: 20}
monad %Maybe.Just{} do
a <- %Just{just: 2}
b <- %Nothing{}
return(a * b)
end
#=> %Nothing{}
# =============================
# DIRECT COMPARISION WITH MAYBE
# =============================
# Note that the insides of both blocks are IDENTICAL,
# but do these operations "inside" if the wrapping type.
# Behaviour is "the same" as interpreted by each datatype.
monad [] do
a <- return(2) # [2]
b <- return(4) # [4]
return(a + b)
end
#=> [6]
monad %Maybe.Just{} do
a <- return(2) # %Just{just: 2}
b <- return(4) # %Just{just: 4}
return(a + b)
end
#=> %Just{just: 6}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment