int err = socket(...) if ( err < 0 ) { do_something; }
err = listen(...) if ( err < 0 ) { do_something; }
Haskell's bind operator >>= makes abstracting this really simple. I wish I had it in C.
int err = socket(...) if ( err < 0 ) { do_something; }
err = listen(...) if ( err < 0 ) { do_something; }
Haskell's bind operator >>= makes abstracting this really simple. I wish I had it in C.
For example, for the `if (err) {...}` cases, this is just the `ExceptT` monad transformer.
With regard to understandability, using error throwing code in Haskell is really easy. Implementing it is slightly more difficult, but so is implementing a C compiler. I mean, we shouldn't judge the utility of a thing based on whether the implementation of the thing could be understood by a child. By that measure, children would be incapable of using facebook, because they could not build it.
>you don't have to write these checks every single time
But in real-world applications, the way you react to errors would differ from function to function. Some functions would print a notification to a logfile and return early. Some would terminate the program and send an email to an admin. Some would activate a red "offline" indicator somewhere in a program.
runService=
s <- note SocketConnectionError $ socket AF_INET ...
note CouldNotListen $ listen s 5
note CouldNotBind $ bind s ...
forever $ do
client <- note CouldNotAccept $ accept s
response <- serveRequest client
...
The signatures of socket, bind, etc, would look like (for example): socket :: ExceptT SocketError IO Int
listen :: Int -> Int -> ExceptT ListenError IO ()
Then, at top level main = runExceptT runService >>=
either handleError pure
handleError (SocketConnectionError rsn) = <try again, maybe>
handleError ...
The key here is that error handling is factored out. The 'runService' function expresses concisely all the steps taken, and the entire concern of error handling is factored out into the 'handleError' function, whose behavior I can actually change based on what I may want. In a C implementation, changing error handling strategies, would mean passing some kind of flag in (you could rebuild exceptions using setjmp/longjmp, but meh).When trying to solve a problem by thinking it through, don't most people think imperatively? Ie by a sequence of steps (statements) that modify the world around them (state) to reach the goal?
It feels like I'm leaning to the imperative side. When breaking down the problem into substeps, I'm already thinking about the sequencing which will later dictate the scheduling.
I've been teaching Scratch[1] to 11-13 year olds for a few years now, and most seem to pick it up pretty quick. However a few struggle (while still being motivated enough to keep trying). Would be interesting to see how it went with a functional Scratch version.
That's not scheduling, that's a data dependency which functional style handles very well. Imperative would be more like deciding you have to unpack the charger and then unpack the phone and then charge the phone, when in fact it's fine to unpack them in either order. http://www.lihaoyi.com/post/WhatsFunctionalProgrammingAllAbo... has an extended example.
Do you have a source? I have a vague recollection of a paper doing some research on that, but cannot find it. If I'm not mistaken, results weren't that clear cut.