Skip to content

Commit 689677b

Browse files
committed
day 02: refactor solution to use fold
1 parent 0e2060b commit 689677b

File tree

2 files changed

+38
-17
lines changed

2 files changed

+38
-17
lines changed

day02/README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ The command typings given in the exercise closely resemble the data type declara
88
For debugging purposes, I made my type implement the "Show" class and implemented the "show" method for my type, as shown in this post:
99
* [StackOverflow: "Haskell: Deriving Show for custom type"](https://stackoverflow.com/a/6082118/5424404)
1010

11+
After having implemented the solutions for both parts, I realized that I could use a folding operation to apply the position changes dictated by the given commands.
12+
I learned that `foldr` and `foldl` have different results if the combinator function (`applyCommandPartTwo`, in this case) is not associative.
13+
The combination function's arguments are also flipped:
14+
* [StackOverflow: "Haskell - foldl and foldr?"](https://stackoverflow.com/a/13280185/5424404)
15+
1116
## File structure
1217
* [`./day02.hs`](./day02.hs): My solution for part one of this puzzle
1318
* [`./input.txt`](./input.txt): My personal puzzle input for this challenge

day02/day02.hs

Lines changed: 33 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ instance Show Command where
77
main = do
88
input <- readFile "input.txt"
99
let parsed = parseInput input
10-
(endHor1,endDep1) = calculateEndPosition parsed (0,0)
10+
(endHor1,endDep1) = calculateEndPositionPartOne parsed
1111
putStrLn ("Solution to part one: " ++ show (endHor1 * endDep1))
12-
let (endHor2, endDep2, _) = calculateEndPosition2 parsed (0,0,0)
12+
let (endHor2, endDep2, _) = calculateEndPositionPartTwo parsed
1313
putStrLn ("Solution to part two: " ++ show (endHor2 * endDep2))
1414

1515
{-|
@@ -24,26 +24,42 @@ parseInput input = map (parseCommand . words) (lines input) where
2424
| cmd == "up" = Up (read amt)
2525

2626
{-|
27-
Calculates the position (new horizontal position, new depth) if a submarine starting at (horizontal position, depth) follows all of the given commands.
27+
Calculates the end position (horizontal position, depth) of the submarine when applying the given set of commands
28+
using the interpretation of part one of the puzzle.
2829
29-
>>> calculateEndPosition [Forward 5, Down 5, Forward 8, Up 3, Down 8, Forward 2] (0,0)
30+
>>> calculateEndPositionPartOne [Forward 5, Down 5, Forward 8, Up 3, Down 8, Forward 2]
3031
(15,10)
3132
-}
32-
calculateEndPosition :: [Command] -> (Int, Int) -> (Int, Int)
33-
calculateEndPosition [] (h,d) = (h,d)
34-
calculateEndPosition ((Forward amt):cmds) (h,d) = calculateEndPosition cmds (h + amt, d)
35-
calculateEndPosition ((Down amt):cmds) (h,d) = calculateEndPosition cmds (h, d + amt) -- note that "down" increases the depth
36-
calculateEndPosition ((Up amt):cmds) (h,d) = calculateEndPosition cmds (h, d - amt)
33+
calculateEndPositionPartOne :: [Command] -> (Int, Int)
34+
calculateEndPositionPartOne = foldl applyCommandPartOne (0,0) -- partial application of foldr
3735

3836
{-|
39-
Calculates the position (new horizontal position, new depth, new aim) if a submarine starting at
40-
(horizontal position, depth, aim) follows all of the given commands with the part two interpretation.
37+
Applies the position (horizontal position, depth) update given through a command,
38+
by the interpretation of part one of the puzzle.
39+
-}
40+
applyCommandPartOne :: (Int, Int) -> Command -> (Int, Int)
41+
applyCommandPartOne (hor,dep) (Forward amt) = (hor + amt, dep)
42+
applyCommandPartOne (hor,dep) (Down amt) = (hor, dep + amt) -- note that "down" increases the depth
43+
applyCommandPartOne (hor,dep) (Up amt) = (hor, dep - amt)
44+
45+
{-|
46+
Calculates the end position (horizontal position, depth, aim) of the submarine when applying the given set of commands
47+
using the interpretation of part two of the puzzle.
4148
42-
>>> calculateEndPosition2 [Forward 5, Down 5, Forward 8, Up 3, Down 8, Forward 2] (0,0,0)
49+
>>> calculateEndPositionPartTwo [Forward 5, Down 5, Forward 8, Up 3, Down 8, Forward 2]
4350
(15,60,10)
4451
-}
45-
calculateEndPosition2 :: [Command] -> (Int, Int, Int) -> (Int, Int, Int)
46-
calculateEndPosition2 [] (hor,dep,aim) = (hor,dep,aim)
47-
calculateEndPosition2 ((Forward amt):cmds) (hor,dep,aim) = calculateEndPosition2 cmds (hor + amt, dep + aim*amt, aim)
48-
calculateEndPosition2 ((Down amt):cmds) (hor,dep,aim) = calculateEndPosition2 cmds (hor, dep, aim + amt)
49-
calculateEndPosition2 ((Up amt):cmds) (hor,dep,aim) = calculateEndPosition2 cmds (hor, dep, aim - amt)
52+
calculateEndPositionPartTwo :: [Command] -> (Int, Int, Int)
53+
calculateEndPositionPartTwo = foldl applyCommandPartTwo (0,0,0) -- partial application of foldl
54+
55+
{-|
56+
Applies the position (horizontal position, depth, aim) update given through a command,
57+
by the interpretation of part two of the puzzle.
58+
59+
>>> applyCommandPartTwo (5,0,0) (Down 5)
60+
(5,0,5)
61+
-}
62+
applyCommandPartTwo :: (Int, Int, Int) -> Command -> (Int, Int, Int)
63+
applyCommandPartTwo (hor,dep,aim) (Forward amt) = (hor + amt, dep + aim*amt, aim)
64+
applyCommandPartTwo (hor,dep,aim) (Down amt) = (hor, dep, aim + amt)
65+
applyCommandPartTwo (hor,dep,aim) (Up amt) = (hor, dep, aim - amt)

0 commit comments

Comments
 (0)