mirror of
https://codeberg.org/JasterV/aoc2024-haskell.git
synced 2026-04-26 18:10:05 +00:00
refactor: Make implementation less redundant
This commit is contained in:
parent
36fbdd5864
commit
6e55a067dc
1 changed files with 21 additions and 29 deletions
50
src/Day1.hs
50
src/Day1.hs
|
|
@ -5,7 +5,7 @@ module Day1
|
||||||
where
|
where
|
||||||
|
|
||||||
import Control.Exception (try)
|
import Control.Exception (try)
|
||||||
import qualified Data.Bifunctor as Bifunctor
|
import qualified Data.Bifunctor as BF
|
||||||
import Data.Either
|
import Data.Either
|
||||||
import Data.List (sort)
|
import Data.List (sort)
|
||||||
import Text.Read (readEither)
|
import Text.Read (readEither)
|
||||||
|
|
@ -19,16 +19,18 @@ data ParseError
|
||||||
deriving (Show)
|
deriving (Show)
|
||||||
|
|
||||||
data Error
|
data Error
|
||||||
= ReadFileError String
|
= ReadFileError FilePath IOError
|
||||||
| ParseInputError [ParseError]
|
| ParseInputError ParseError
|
||||||
deriving (Show)
|
deriving (Show)
|
||||||
|
|
||||||
partOne :: String -> IO (Either Error Int)
|
partOne :: String -> IO (Either Error Int)
|
||||||
partOne filepath = do
|
partOne filepath = do
|
||||||
result <- tryReadFile filepath
|
result <- try (readFile filepath)
|
||||||
case result of
|
case result of
|
||||||
Left readError -> return (Left readError)
|
Left readError ->
|
||||||
Right contents -> return (calculateScore <$> parseInput contents)
|
return $ Left (ReadFileError filepath readError)
|
||||||
|
Right contents ->
|
||||||
|
return $ calculateScore <$> BF.first ParseInputError (parseInput contents)
|
||||||
where
|
where
|
||||||
-- To calculate the overall score we just need to
|
-- To calculate the overall score we just need to
|
||||||
-- sort the lists and calculate the distances between each element
|
-- sort the lists and calculate the distances between each element
|
||||||
|
|
@ -38,10 +40,10 @@ partOne filepath = do
|
||||||
|
|
||||||
partTwo :: String -> IO (Either Error Int)
|
partTwo :: String -> IO (Either Error Int)
|
||||||
partTwo filepath = do
|
partTwo filepath = do
|
||||||
result <- tryReadFile filepath
|
result <- try (readFile filepath)
|
||||||
case result of
|
case result of
|
||||||
Left readError -> return (Left readError)
|
Left readError -> return $ Left (ReadFileError filepath readError)
|
||||||
Right contents -> return (calculateScore <$> parseInput contents)
|
Right contents -> return $ calculateScore <$> BF.first ParseInputError (parseInput contents)
|
||||||
where
|
where
|
||||||
-- To calculate the overall score we need to sum all the similarity scores
|
-- To calculate the overall score we need to sum all the similarity scores
|
||||||
-- of each element from the left list applied to the right list
|
-- of each element from the left list applied to the right list
|
||||||
|
|
@ -51,17 +53,15 @@ partTwo filepath = do
|
||||||
similarity id ids = id * count id ids
|
similarity id ids = id * count id ids
|
||||||
count x = length . filter (== x)
|
count x = length . filter (== x)
|
||||||
|
|
||||||
parseInput :: String -> Either Error ([LocationID], [LocationID])
|
parseInput :: String -> Either ParseError ([LocationID], [LocationID])
|
||||||
parseInput input = Bifunctor.first ParseInputError $ unzip <$> parseLines (lines input)
|
parseInput xs =
|
||||||
|
case errors of
|
||||||
parseLines :: [String] -> Either [ParseError] [(LocationID, LocationID)]
|
[] -> Right parsedInput
|
||||||
parseLines xs =
|
(parseError : _) -> Left parseError
|
||||||
if null errors
|
|
||||||
then Right parsedLines
|
|
||||||
else Left errors
|
|
||||||
where
|
where
|
||||||
errors = lefts $ map (parseWords . words) xs
|
parse = map (parseWords . words) . lines
|
||||||
parsedLines = rights $ map (parseWords . words) xs
|
errors = lefts $ parse xs
|
||||||
|
parsedInput = unzip $ rights $ parse xs
|
||||||
|
|
||||||
parseWords :: [String] -> Either ParseError (LocationID, LocationID)
|
parseWords :: [String] -> Either ParseError (LocationID, LocationID)
|
||||||
parseWords [left, right] = do
|
parseWords [left, right] = do
|
||||||
|
|
@ -69,24 +69,16 @@ parseWords [left, right] = do
|
||||||
rightLocation <- parseRight
|
rightLocation <- parseRight
|
||||||
return (leftLocation, rightLocation)
|
return (leftLocation, rightLocation)
|
||||||
where
|
where
|
||||||
parseLeft :: Either ParseError LocationID
|
|
||||||
parseLeft =
|
parseLeft =
|
||||||
Bifunctor.first
|
BF.first
|
||||||
(ParseLocationError left)
|
(ParseLocationError left)
|
||||||
(readEither left :: Either String LocationID)
|
(readEither left :: Either String LocationID)
|
||||||
|
|
||||||
parseRight :: Either ParseError LocationID
|
|
||||||
parseRight =
|
parseRight =
|
||||||
Bifunctor.first
|
BF.first
|
||||||
(ParseLocationError right)
|
(ParseLocationError right)
|
||||||
(readEither right :: Either String LocationID)
|
(readEither right :: Either String LocationID)
|
||||||
|
|
||||||
-- If the line does not contain exactly two words,
|
-- If the line does not contain exactly two words,
|
||||||
-- it is considered an error
|
-- it is considered an error
|
||||||
parseWords xs' = Left $ ParseLineError (unwords xs')
|
parseWords xs' = Left $ ParseLineError (unwords xs')
|
||||||
|
|
||||||
tryReadFile :: String -> IO (Either Error String)
|
|
||||||
tryReadFile filepath = Bifunctor.first (const $ ReadFileError filepath) <$> io
|
|
||||||
where
|
|
||||||
io :: IO (Either IOError String)
|
|
||||||
io = try (readFile filepath)
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue