Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Brilliant write up.

> There is also a school of thought that you should start Haskell by teaching the IO monad first, but I am not convinced: in my experience, if someone gets exposed to IO early on, they will contaminate all their functions with IO. They will essentially end up writing Java in Haskell.

I don't think this is such a bad starting place. Crawling before walking. Purifying an (unnecessarily-) IO function into an ordinary function is a good exercise.

Trying to enforce non-IO from the start would be like enforcing 'no new keyword & factories only' in another language.



One of the reasons I liked the Haskell Wikibook [1] when trying to learn Haskell was that it didn't concern the reader with the IO monad until much later. It just presented 2 forms of using the language, a) normal functional style, b) an "imperative" "do" style, and then showed how they could be used together and when.

That was enough to do most basic tasks and only later was it explained why they can't be mixed directly.

[1] https://en.wikibooks.org/wiki/Haskell


I feel like the hard part is that, if you dive in early on with imperative-style code, it's really easy to try and do everything else the imperative "style" too...until you can't, or you run into some weird behavior stemming from how IO works, at which point you just end up super confused.

Starting without IO makes sure that you actually start to "get" how the language functions, so that once you jump into IO, the weird parts and how to mix it in with the logic written elsewhere makes a lot more sense.


> Purifying an (unnecessarily-) IO function into an ordinary function is a good exercise.

Agree! And I would add that you can "purify" a monadic function without having to rewrite it in non-monadic style. You can make it polymorphic over all monads and relegate the "impurity" to monadic functions that you pass as arguments/dependencies. A trivial example:

  twice :: IO ()
  twice = do
      putStrLn "foo"
      putStrLn "foo"
  
  twice' :: forall m. m () -> m ()
  twice' action = do 
      action
      action
This is not that different to having a Spring bean that doesn't perform any effect directly—say, a direct invocation to "Instant.now()"—but instead receives a "Clock" object through dependency injection.

Haskell lets you express the idea of "program logic that only has effects through its dependencies" by being polymorphic over all monads.


I agree. Haskell is a really good imperative language if that's what you want to use it for.

And allowing beginners to write actual meaningful programs is a huge pedagogical benefit.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: