3 ms·
Thanks for your explanations! 2&4 make a lot of sense. 1, and even more so 3, lead to more questions than they answer, in my opinion. Monads appear to be an abs
by microtherion 7y ago
Thanks for your explanations! 2&4 make a lot of sense. 1, and even more so 3, lead to more questions than they answer, in my opinion. Monads appear to be an absolutely indispensible aspect of most substantial Haskell programs, but to me, they just look incomprehensible. I understand the advantages of a pure programming model for formal reasoning about programs, but in terms of communicating an intent with a program, I can't help thinking that the cure offered by Monads is far worse than the disease of mutable state.
- rovolo 7y ago1) I'm guessing that the point of confusion is 'does nothing - it's redundant'. This 'do block' is combining multiple ScottyMs together into one ScottyM. The 'Monad' interface means that ScottM tells you how to combine them together. You could write this in Java as interface ScottM { ScottM plusRoute(ScottM next) } get("/", ... ) .plusRoute(get("/:short", ...)) .plusRoute(...) The difference is that there's lots of library functions which can work on a Monad, but you'll have to write/import all of the utility methods to combine your custom RequestHandler interface. 3) > How is that request passed into "app"? "app" doesn't execute handle the request, it is a factory method returning a request-handler of type 'ScottM'. You hook in the 'app' to the webserver on line 94: scotty 3000 (app rConn) You might be getting confused by the "R.Connection" argument; that's the connection to the database, not the HTTP request. > How is it passed into the "get"? scotty will apply the "get" to the HTTP request encapsulated as an IO monad. I'm not sure what the internals of 'scotty' are like, but you're basically calling 'ScottM.handle(IOStream)'. 'get' is a 'ScottM' request handler which you combined with the other route handler. > How is it passed to "param"? "param" returns "ActionM", which is basically a "Consumer<IOStream>". The rest of the lines here are also "ActionM" which get combined together. The 'get' will in effect call "handle(IOStream)". Really understanding the niceties of this would require playing around with IO in haskell for a bit. The 'do' syntax is somewhat incomprehensible when you first see it because it is syntactic sugar for a pattern which is used in other languages, but which they don't name. You might have more success learning what it's doing by getting rid of the syntactic sugar and renaming (>>) and (>>=) to more familiar stuff from Java. Maybe it would be best to try it out using Java's CompletableFuture or Stream. https://en.wikibooks.org/wiki/Haskell/do_notation https://en.wikibooks.org/wiki/Haskell/do_notation
- phlakaton 7y agoThe advantage of monads is that they whisk away a bunch of boring, repetitive boilerplate code that nobody wants to write and that people will even go so far in other languages as to create a bunch of global/thread-local/hidden-context variables to avoid writing! The downside is that the abstraction and its applications, maybe a bit like pointers, do take a while to really master. Particularly when you start composing monad types to make other monads, as Scotty does with IO.