Haskell
In recent months, I’ve started looking deeper into FP, looking at concepts like monad transformers and the State and Reader monads.
I initially did this by digging further into FSharpPlus, a library that enables more advanced FP in F#. That’s been a fine approach for the most part, but I gradually found myself referring to both F# and Haskell articles online to better grok the concepts.
Over time, I decided there would be value in just studying directly in Haskell itself, where the concepts are (I believe it’s fair to say) implemented more purely without the idiosyncrasies and limitations of .NET. I’ve been reading through the PDF version of the Haskell book on Wikibooks, going through at slow pace in my free time. (There’s no rush, after all, and I might even make this a lifelong project depending on how it goes.)
Ultimately, though, you can only learn so much from just reading, so I’ve been trying to practice more coding in Haskell.
I’m currently working in a new practice repo (days-away) on a very simple Haskell console application that takes a CSV of dates and descriptions and prints out the number of days since, or until, each date. (I’ve done this before in C#.) It’s basic stuff, but actually coding in Haskell is definitely helping me understand the concepts more, and through this project I’ve been able to get some basic experience with monad transformers. (It’s still tricky to understand which context I’m at times, but I’m improving.)
I aim to avoid LLMs for code generation (as the point here is to learn), but they are quite helpful for some reviewing and unblocking me when I get stuck. (However, I must admit to using one to generate the formatCommas library function today, as how to do that was not very clear to me. It was much more manual than expected, but perhaps there’s a better way to do it.)
Anyway, here’s the current version of my main function:
main :: IO ()
main =
runExceptT computation >>= either putStrLn return
where
computation :: ExceptT String IO () = do
fileName <- checkArgs
checkExtension fileName
content <- readSmallFile' fileName
let lines_ = T.lines content
lineCount = show $ length lines_
charCount = show $ T.length content
results = traverse (runExceptT . parseLine) lines_
liftIO $ do
putStrLn $ "This file has " ++ lineCount ++ " line(s) and " ++ charCount ++ " character(s)."
(errors, summaries) <- partitionEithers <$> results
printSummaries summaries
printErrors errors
It’s undoubtedly not great Haskell, but I’m pretty pleased I’ve been able to put something like this together (and understand it), and I look forward to tweaking it more and applying what I learn in F# as well.
Edit: I came across a nice interview with Simon Jones, one Haskell’s co-creators: “Co-Creator of Haskell: Why Learn Functional Programming, Useless vs Useful Languages.”