Day 2

Starting with the parse step, the input is of the form 11-22,15-17,.... So we first split on commas, for each item in the list (of the form "11-22"), we can split again on "-", and finally, use read to parse them to integers.

import Data.List.Split (splitOn)

parse :: String -> [[Int]]
parse = map (map read . splitOn "-") . splitOn ","

We can move onto the problem itself now.

Part 1

The check for invalidity for an integer in Part 1 requires us to simply split the string in half and ensure that the two halves are identical, this is easily produced using splitAt:

invalid :: Int -> Bool
invalid n = l == r
  where
    s = show n
    (l, r) = splitAt (length s `div` 2) s

With that in place, we can define the solution to part 1. range is a utility to iterate through the pair, we then filter out invalid items and add everything up:

range [a, b] = [a .. b]

p1 i = sum $ concatMap (filter invalid . range) i

Part 2

This part requires a slight modification to the invalidity check. We now need to check for any number of repeating substrings, so “123123123” is invalid because it is formed from "123" + "123" + "123". The methodology here is slightly involved, first we get all prefixes of the input using inits. We can filter out the initial empty prefix with tail. Upon repeated cyling the prefixes, if we are able to form the original string, then the string can be considered invalid!

import Data.List (inits, isPrefixOf)
invalid2 :: Int -> Bool
invalid2 n = any ((s `isPrefixOf`) . cycle) $ tail $ inits l
  where
    s = show n
    (l, _) = splitAt (length s `div` 2) s

Then, part 2 is defined like so:

p2 i = sum $ concatMap (filter invalid2 . range) i

Finally, a main function to wrap it all up:

main = do
  n <- parse <$> getContents
  print $ p1 n
  print $ p2 n