Skip to content

Instantly share code, notes, and snippets.

@maxov
Last active January 1, 2016 08:49
Show Gist options
  • Save maxov/8120700 to your computer and use it in GitHub Desktop.
Save maxov/8120700 to your computer and use it in GitHub Desktop.
Monads in LiveScript

This is an implementation of monads in a way that is pretty for LiveScript(given its amazing syntactic structures). This was originally a comment for LiveScript #426.

# What this function('liveify') does is take a normal, Haskell-ish monad constructor function,
# and convert it so that it works in the livescript do <- chain syntax.
# It returns a function that takes the function's normal args along with a callback(possibly),
# and apply the callback to the function's result(or bind it, in this case).
liveify = (fn) ->
| fn.length == 0 => # in the case of something like readLn
(callback = ->) -> fn!bind callback
| otherwise =>
(...args) ->
| args.length == fn.length => fn ... # in the case of no callback
| otherwise => let [...init, last] = args
# the magic of monads is preserved: the value is passed along with 'bind'
(fn ...init).bind last
# We can write our monad simply:
class IO
(@val) ~>
# we 'liveify' unit so that it can be used nicely in the do <- notaiton
@unit = liveify @@
bind: (callback) -> callback @val
# We must 'liveify' the monadic functions so they work with our syntax,
# otherwise they are super simple
putStrLn = liveify (msg) -> IO.unit alert msg
readLn = liveify (msg) -> IO.unit prompt msg
# You can essentially drop this code right into Haskell.
# Feel like haskell yet?
main = do
x <- readLn 'enter a number!'
putStrLn "you entered: #x"
y <- readLn 'enter another number!'
putStrLn "you entered: #y"
putStrLn "I added them up for you: #{parseInt(x) + parseInt(y)}"
# Note that lines without a 'variable <- expression' statement don't continue the function nesting,
# and so aren't strictly proper, this can become a problem with promises and such.
# If needed, this can be fixed by prepending an empty '<-' to those lines:
main = do
x <- readLn 'enter a number!'
<- putStrLn "you entered: #x"
...
# This isn't, strictly speaking, how Haskell would interpret this.
# It would be closer to make main a function, but that is really simple,
# plus, it returns the value! How convenient. Also, it hints that main is
# a monadic function with the extra arrow(the 'do' is not really needed anymore).
main = do ->
x <- readLn 'enter a number!'
putStrLn "you entered: #x"
y <- readLn 'enter another number!'
putStrLn "you entered: #y"
putStrLn "I added them up for you: #{parseInt(x) + parseInt(y)}"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment