Day 1

Parse the input:

parse :: String -> [Int]
parse = map f . lines
    where f ('L':r) = negate (read r)
          f ('R':r) = read r

Part 1

Rotate the dial starting at 50, and count the number of times we stop at zero on the way. Of note is that the dial cycles back to zero after 100, so our check mustn’t just be == 0 but rather, mod n 100 == 0:

count :: (a -> Bool) -> [a] -> Int
count pred = length . filter pred

clicks :: [Int] -> Int
clicks = count ((== 0) . (`mod` 100)) . scanl (+) 50

Thus, the solution to the first part is given by:

p1 :: [Int] -> Int
p1 = clicks

Part 2

This part is ever so slightly different, instead of the number of times we stop are zero, we are required to additionally calculate the number of times we pass through zero.

To think of this a bit differently, the first part has lower degree of precision: we only perform the check after the dial is fully rotated. The second part requires us to perform the check with higher degree of precision: after each movement by 1. Thus, if we modify our list to change one rotation of size N into N rotations of size 1, we will be able to reuse our clicks method:

transform :: Int -> [Int]
transform n = replicate (abs n) (signum n)

p2 :: [Int] -> Int
p2 = clicks . concatMap transform

Finally, a main function to wrap it all up:

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