DEV Community


Posted on

An insight about functional programming

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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...

Discussion (0)