You are reading a single comment by @wence and its replies. Click here to read the full conversation.
  • My solution to day 3 in Haskell. AoC is the first thing I have ever written in Haskell and it shows! I am an aerodynamics engineer who uses MATLAB and Python to basically just deal with matrix operations. It's been tricky to adjust to a functional way of thinking & where everything is not just a matrix of doubles!

    main = do
        input <- fmap lines $ readFile "input_day03.txt"
        print $ countLetters (tail $ countTrees (every 1 input) [0,3..]) '#'
        print $ product $ countAllTrees input [1,1,1,1,2] [1,3,5,7,1]
    
    countTrees :: [String] -> [Int] -> String
    countTrees [] _ = []
    countTrees (x:xs) (y:ys) = [x !! (y `mod` length x)] ++ countTrees xs ys
    
    countLetters :: String -> Char -> Int
    countLetters str c = length $ filter (== c) str
    
    every :: Int -> [String] -> [String]
    every n (x:xs) = [x] ++ every n (drop (n-1) xs)
    every _ [] = []
    
    countAllTrees :: [String] -> [Int] -> [Int] -> [Int]
    countAllTrees input (x:xs) (y:ys) = 
            [countLetters (tail $ countTrees (every x input) [0,y..]) '#'] 
            ++ countAllTrees input xs ys
    countAllTrees _ [] _ = []
    
  • Looks good!

    Try and train yourself out of the habit of adding a single entry to the start of a list by using ++ and instead cons it on the front with :.

    E.g., write

    every n (x:xs) = x : every n (drop (n-1) xs)
    -- Rather than
    every n (x:xs) [x] ++ every n (drop (n-1) xs)
    

    (:) is O(1) because you're just adding a node to the head of a linked list, whereas ++ is O(n) in the length of the first list because Haskell has to walk to the end of the first list before appending the second one.

    Although it doesn't really matter here because the first list is only length one, it's an antipattern one tries to avoid. e.g. compare the runtime performance of

    rev :: [a] -> [a]
    rev (x:xs) = rev xs ++ [x]
    rev [] = []
    -- with
    
    rev' :: [a] -> [a]
    rev' xs = revH xs []
      where
        revH (x:xs) ys = revH xs (x:ys)
        revH [] ys = ys
    

    (Getting ready to teach intro Haskell again...)

  • Thank you for this! Really useful. I'm planning to carry Haskell on past the advent of code, I feel like it is not a quick language to get competent in!

    Out of interest, in what capacity do you teach into Haskell?

About

Avatar for wence @wence started