I’m learning functional programming and writing things down as I go. Some of my understanding may be incomplete or wrong, and I expect to refine it in the fullness of time.
After a discouraging experience with building a tiny web app in Haskell, I got a convenient opportunity to apply Haskell to a small real world problem in one of my projects.
The idea is to load a graph out of the database, find the cycles, and write back the results.
My hopes for database libraries were low after looking at Persistent and Esqueleto, but somehow I stumbled into Hasql a few days later. Hasql is a really nice library, and exactly what I was looking for:
It’s a brand new project, so I had to wait a few days until a working version appeared in Stackage.
It’s also very light on documentation, which made things hard for me, primarily due to its use of monads and monad transformers.
I don’t understand monads yet, but I learned enough to make my queries work. It took me quite a while to figure out how to collect results of multiple queries into a single result. It boiled down to this:
-- take a list of node IDs and generate a list of nodes with their edges graph <- forM nodeIds $ \((nodeId, _)) -> do edges :: [(NodeId, Bearing)] <- getEdges nodeId return $ getEdgyNode nodeId edges
Another cool thing I learned was the
on function from
Data.Function, which allowed me to express a comparison for
maximumBy very cleanly:
maximumBy (compare `on` relativeBearing) nextEdges where relativeBearing edge = normaliseBearing (bearing edge - bearing currEdge)
This function finds the edge with a maximum relative bearing, so I needed to calculate the relative bearing for each edge and use the result for comparison. In my initial solution, I wrote the comparison function manually:
maximumBy cmpRelativeBearing nextEdges where relativeBearing edge = normaliseBearing (bearing edge - bearing currEdge) cmpRelativeBearing edge1 edge2 = compare (relativeBearing edge1) (relativeBearing edge2)
on function is defined like this, so I could use it to express my comparison function:
(*) `on` f = \x y -> f x * f y
Some other thoughts: