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.
Last active
January 1, 2016 08:49
-
-
Save maxov/8120700 to your computer and use it in GitHub Desktop.
Monads in LiveScript
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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