Skip to content

Instantly share code, notes, and snippets.

@okkero
Last active February 7, 2018 12:58
Show Gist options
  • Save okkero/7c2eb0fd8511d14c763b80c0b9bfc5ed to your computer and use it in GitHub Desktop.
Save okkero/7c2eb0fd8511d14c763b80c0b9bfc5ed to your computer and use it in GitHub Desktop.
module Main where
import Control.Monad
import Data.Char
import Data.Either
import Data.List.Split
type PhonebookError = String
data PhonebookEntry = PhonebookEntry
{ pe_name :: String
, pe_numbers :: [Int]
} deriving Show
parseName :: String -> Either PhonebookError String
parseName =
foldr
(\c result ->
result >>= \name ->
if (c < 'a' || c > 'z') && (c < 'A' || c > 'Z') && c /= ' ' then
Left $ "Invalid character " ++ [c] ++ "!"
else
Right $ c : name
)
(Right "")
parsePhoneNumber :: String -> Either PhonebookError Int
parsePhoneNumber ('0' : _) = Left "Phone number cannot begin with zero!"
parsePhoneNumber phoneNumber =
foldl
(\result c ->
let n = ord c - ord '0'
in result >>= \number ->
if n < 0 || n > 9 then
Left $ "Invalid Character " ++ [c] ++ "!"
else
Right $ 10 * number + n
)
(Right 0)
phoneNumber
parsePhoneNumbers :: String -> Either PhonebookError [Int]
parsePhoneNumbers =
mapM parsePhoneNumber . words
parseArguments :: [String] -> Either PhonebookError PhonebookEntry
parseArguments [name, phoneNumbers] =
liftM2 PhonebookEntry (parseName name) (parsePhoneNumbers phoneNumbers)
parseArguments xs = Left $ "Expected 2 arguments, got " ++ (show $ length xs) ++ "!"
parseLine :: String -> Either PhonebookError PhonebookEntry
parseLine = parseArguments . splitOn ": "
main :: IO ()
main = do
let goodPhonebook = "John Doe: 1337 69 420"
malformedPhonebook = "This is a malformed phone book!"
mapM_
(print . fromRight "Uh-oh, that doesn't work this way!" . (show <$>) . parseLine)
[goodPhonebook, malformedPhonebook]
pure ()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment