Advent of Code 2022 - Day 3 Bonus: Split in Half
While writing up the post for Advent of Code Day 3, I came across a small improvement to my splitInHalf
function. This function takes a string and returns both parts of it. Here's the original:
splitInHalf :: String -> [String]
splitInHalf s = [take size s, drop size s]
where
size = length s `div` 2
Prelude (essentially Haskell's standard library) has a function splitAt
, which we can use:
splitInHalf :: String -> [String]
splitInHalf s = [s1, s2]
where
(s1, s2) = splitAt (length s `div` 2)
Converting from the tuple to the list should be unnecessary. Let's try chunksOf
?
splitInHalf :: String -> [String]
splitInHalf s = chunksOf (length s `div` 2) s
Point Free?
We can convert the above function into a point-free style. Look at the form of our functions:
splitInHalf :: String -> [String]
halfLength :: String -> Int -- (`div` 2) . length
chunksOf :: Int -> String -> [String]
(r ->)
is an instance of a monad, so let's factor (String ->)
out from our types and see what's left. We replace each function (String -> a)
with m a
:splitInHalf :: m [String]
halfLength :: m Int
chunksOf :: Int -> m [String]
So is there a function that can take our halfLength
and chunksOf
and returns our function splitInHalf
? It would have the type of m a -> (a -> m b) -> m b
. It does exist, it's called "bind" (>>=
), and it's kinda the core functionaly of monads!
splitInHalf :: String -> [String]
splitInHalf = (`div` 2) . length >>= chunksOf
Using the flipped version of bind brings another new perspective:
splitInHalf :: String -> [String]
splitInHalf = chunksOf =<< (`div` 2) . length
This looks similar to our original, but composed of functions instead of values.
Advent of Code 2022 Series
This post is part of a series describing my Haskell solutions to Advent of Code 2022.
Main Post: Day 3: Rucksack Reorganization
Cheers!