Week 3 Lecture 1
hs
1import Control.Applicative (Alternative (..), asum)2import Control.Monad (ap, liftM, void)3import Data.Char (isDigit, isSpace, ord)45stringToInt1 :: String -> Int6stringToInt1 s = loop 0 s7 where8 loop acc [] = acc9 loop acc (c : cs) =10 let c' = ord c - ord '0'11 in loop (acc * 10 + c') cs1213stringToInt2 :: String -> Maybe Int14stringToInt2 s = loop 0 s15 where16 loop acc [] = Just acc17 look acc (c : cs) =18 if isDigit c19 then20 let c' = ord c - ord '0'21 in loop (acc * 10 + c') cs22 else Nothing2324-- where did stringToInt3 go???2526stringToInt4 :: String -> Maybe (Int, String)27stringToInt4 "" = Nothing28stringToInt4 (c : cs) = if isDigit c then loop 0 (c : cs) else Nothing29 where30 loop acc "" = Just (acc, "")31 loop acc (c : cs) = if isDigit c then loop ((ord c - ord '0') + acc * 10) cs else Just (acc, c : cs)3233hasLeadingSpace :: String -> Maybe String34hasLeadingSpace (c : cs) = if c == ' ' then Just cs else Nothing3536stringToInts :: String -> Maybe ((Int, Int), String)37stringToInts s =38 case stringToInt4 s of39 Nothing -> Nothing40 Just (x, s') -> case hasLeadingSpace s' of41 Just s'' -> case stringToInt4 s'' of42 Just (y, s''') -> Just ((x, y), s''')43 Nothing -> Nothing44 _ -> Nothing4546stringToInts2 :: String -> Maybe ((Int, Int), String)47stringToInts2 s = do48 (x, s') <- stringToInt4 s49 s'' <- hasLeadingSpace s'50 (y, s''') <- stringToInt4 s''51 pure ((x, y), s''')5253data Parser a = Parser ((Int, String) -> Either (Int, String) (a, (Int, String)))5455instance Functor Parser where56 fmap :: (a -> b) -> Parser a -> Parser b57 fmap = liftM5859instance Applicative Parser where60 pure a = Parser $ \s -> Right (a, s)61 (<*>) = ap6263instance Monad Parser where64 Parser a >>= f = Parser $ \s -> do65 (a', s') <- a s66 let (Parser b) = f a'67 b s'6869runParser :: Parser a -> String -> Either String a70runParser (Parser f) s = case f (0, s) of71 Left (pos, err) -> Left ("Parse error at " ++ show pos ++ ": " ++ err)72 Right (a, _) -> pure a7374satisfy :: (Char -> Bool) -> Parser Char75satisfy p = Parser $ \(pos, s) ->76 case s of77 "" -> Left (pos, "Empty input")78 c : (cs) ->79 if p c80 then81 pure (c, (pos + 1, cs))82 else Left (pos, "Invalid character: " ++ [c])8384threeDigits :: Parser (Char, Char, Char)85threeDigits = let s = satisfy isDigit in (,,) <$> s <*> s <*> s8687instance Alternative Parser where88 empty = Parser $ \(pos, s) -> Left (pos, "All branches exhausted")89 (Parser p1) <|> (Parser p2) = Parser $ \s -> case p1 s of90 Left err -> p2 s91 Right a -> pure a9293choice :: [Parser a] -> Parser a94choice = asum9596(<?>) :: Parser a -> String -> Parser a97Parser p <?> e = Parser $ \s -> case p s of98 Left (o, _) -> Left (o, e)99 a -> a100101try :: Parser a -> Parser (Maybe a)102try (Parser p) = Parser $ \(pos, s) -> case p (pos, s) of103 Right (a, (pos', s')) -> Right $ (Just a, (pos', s'))104 Left e -> Right $ (Nothing, (pos, s))105106mymany :: Parser a -> Parser [a]107mymany p =108 choice109 [ do110 x <- p111 xs' <- mymany p112 pure (x : xs')113 , pure []114 ]115116parseDigit :: Parser Int117parseDigit = (\c -> ord c - ord '0') <$> satisfy isDigit118119parseInt :: Parser Int120-- parseInt = do121-- xs <- some parseDigit122-- pure $ foldl' (\acc x -> acc * 10 + x) 0 xs123parseInt = foldl' (\acc x -> acc * 10 + x) 0 <$> some parseDigit124125skipSpaces :: Parser ()126skipSpaces = void $ many (satisfy isSpace)127128parseTwoInts :: Parser (Int, Int)129parseTwoInts = do130 x <- parseInt131 skipSpaces132 y <- parseInt133 pure (x, y)134135getTwoInts :: String -> Either String (Int, Int)136getTwoInts s = runParser (skipSpaces *> parseTwoInts) s137138-- I guess it is halloween139-- We are getting sugars thrown at us at random <*140-- 🫳🍬🍬🍬141142postfix :: Parser a -> Parser b -> Parser a143postfix p1 p2 = p1 <* p2144145parseInts :: Parser [Int]146parseInts = many parseIntThenSpace147 where148 parseIntThenSpace = do149 x <- parseInt150 skipSpaces151 pure x152153eof :: Parser ()154eof = Parser end155 where156 end :: (Int, String) -> Either (Int, String) ((), (Int, String))157 end s@(_, "") = pure ((), s)158 end (pos, _) = Left (pos, "EOF expected")159160instance MonadFail Parser where161 fail s = Parser (\(pos, _) -> Left (pos, s))162163-- I don't provide invalid data to a program so I'm unfamiliar with the situation (thug life)164165-- Spaaace166