/wakamoleguy

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!