In-class-5
Class: CSCE-314
-- 1) Polymorphism: keep only successful results
mapOptional :: (a -> Maybe b) -> [a] -> [b]
mapOptional f xs = [ y | x <- xs, Just y <- [f x] ]
-- Input: a function 'f :: a -> Maybe b'
-- Produces 'b' for some 'a' (returns 'Just b')
-- Fail to produce 'b' (returns Nothing)
-- Input: a list of 'a' type values
-- x <- xs iterates each element x of the input list.
-- Just y <- [f x] is a pattern-match generator
-- If f x is Just y, the pattern match succeeds (y is added).
-- If f x is Nothing, the pattern match fails (no y is produced).
-- Return: "List of all b results for which 'f x' resturned 'Just b'"
-- 'y' refers to type b elements
-- Drops elements where 'f' returns Nothing
-- Usage:
-- ghci> let f x = if even x then Just (x*2) else Nothing
-- ghci> mapOptional f [1..6]
-- [4,8,12]
-- 2) Safe integer parser for a single token using reads
-- Read an Int from a given String
readIntMaybe :: String -> Maybe Int
readIntMaybe s =
case reads s of
[(n,"")] -> Just n
_ -> Nothing
-- 3) Replace non-digit/non-sign with spaces to separate tokens
-- Keep '-' so negative numbers remain intact.
normalizeDigits :: String -> String
normalizeDigits = map f -- No need to input 's' here
where
f c -- Input str is 'c' (a single character)
| isDigit c = c -- Keep digits
| c == '-' = c -- Keep minus signs
| otherwise = ' ' -- Replace everything else with space char
-- 4) Extract integers from messy text
extractInts :: String -> [Int]
extractInts s = mapOptional readIntMaybe (words (normalizeDigits s))
-- 'words' splits the normalized string into tokens (so -123, 45, etc. remain intact).
-- basically makes a list out of a string with space-separated words
-- 5) Variants with Maybe and Either
extractIntsMaybe :: String -> Maybe [Int]
extractIntsMaybe s =
case extractInts s of
(x:xs) -> Just (x:xs)
[] -> Nothing
extractIntsEither :: String -> Either String [Int]
extractIntsEither s =
case extractInts s of
(x:xs) -> Right (x:xs)
[] -> Left "no integers found"