I first touched Haskell >1 year ago, and have studied on and off in the time since, though I haven't touched in a while at present due to being too busy with other things. But one thing I got hung up on - okay, this is probably what every newcomer to Haskell gets hung up on - is the idea that imperative programming is disallowed or made more difficult in Haskell. Now I want to write about a realization I had around the last time I was working with it, because I'm not sure that this is the case.
What is the difference between a function and an action, and how does Haskell treat it differently than other languages? This itself was a question I wasn't sure about after weeks of trying to learn it, and still aren't really sure. But where I'm currently at is that.
In other words, functions are a subset of actions. Every function can be trivially converted to an action. In Haskell, I can take this beautiful functional code:
main = getLine >>= (\a -> getLine >>= (\b -> print $ fibbonaci (read a ::Int) (read b ::Int))) fibbonaci a b = fibbonaciInner a b  fibbonaciInner a b list | length list < 10 = fibbonaciInner (b) (a + b) (list ++ [a + b]) | otherwise = list
And convert it to a typical imperative version:
main = do a <- getLine b <- getLine fibbSeq <- fibbonaci (read a ::Int) (read b ::Int) print fibbSeq fibbonaci :: Int -> Int -> IO [Int] fibbonaci a b = fibbonaciInner a b  fibbonaciInner :: Int -> Int -> [Int] -> IO [Int] fibbonaciInner a b list = if length list < 10 then fibbonaciInner b (a + b) (list ++ [a + b]) else return list
See what I did there? I made the
fibbonaciInner function an IO action that takes arguments, does a computation, and "returns" its value, instead of a function that merely defines a mapping of values.
(Haskellers more experienced than me often say that Haskell
return has nothing to do with what that word means in other languages, but I think it's actually a very good analogy.)
And what this made me realize is that every other language is doing the latter. In a way, is a pure language strictly better than non-pure ones?
Haskell doesn't stop you from doing things imperatively. Other languages force you to be imperative, so that having the option to be pure feels like a constraint.
All I did by converting the function to an imperative style was lose the ability to use it in pure contexts. I can't import the module and
reverse $ fibbonaci x y now (I can use
fmap to get around it, but with the pure version I don't have that extra layer of complexity). But in imperative languages, everything is already impure, even if it doesn't need to be.
I think if you get past seeing it this way, Haskell starts to seem a lot less arcane.
But then, this is coming from someone who still thinks Haskell is arcane and doesn't understand it, so...
As software gets more and more integrated into our lives, the industrialization of its crafting process becomes inevitable. But the over-generalization of software engineering can be crushing the creative side of programming.