Haskell, the same program using monads

As you can see, I wrote a program, for example:

test "12 124 212" = Right [12, 124, 212]

test "43 243 fs3d 2" = Left "fs3d is not a number"

test :: String -> Either String [Int]
test w = iter [] $ words w
    where
        iter acc []     = Right (reverse acc)
        iter acc (x:xs) = if (all isDigit x) then
                              iter ((read x):acc) xs
                          else
                              Left (x++ "is not a number")   

I'm starting to learn monads. Could you show me how to implement it using monads?

+4
source share
2 answers

I think you are looking for traverse/ mapM(they are the same for lists). You can also use readEitherto simplify:

import Data.Traversable (traverse)
import Data.Bifunctor (first)
import Text.Read (readEither)

test :: String -> Either String [Int]
test = traverse parseItem . words

parseItem :: String -> Either String Int
parseItem x = first (const $ x++" is not a number") $ readEither x

, mapM? , . , map, (parseItem , Either String ) :

iter [] = Right []
iter (x:xs) = do
  r <- parseItem x
  rs <- iter xs
  return (r:rs)
+4

, , , :

test :: String -> Either String [Int]
test str = traverse parseNumber (words str)

parseNumber :: String -> Either String Int
parseNumber str
    | all isDigit str = Right (read str)
    | otherwise       = Left (str ++ " is not a number")

, , - , iter . , , . , , traverse - , . , , . , Monad Either Traversable , traverse :

-- This is the same as `traverse` for lists and `Either`
traverseListWithEither :: (a -> Either err b) -> [a] -> Either err [b]
traverseListWithEither f [] = Right []
traverseListWithEither f (a:as) =
    case f a of
      Left err -> Left err
      Right b  -> mapEither (b:) (traverseListWithEither f as)

-- This is the same as the `fmap` function for `Either`    
mapEither :: (a -> b) -> Either e a -> Either e b
mapEither f (Left e)  = Left e
mapEither f (Right a) = Right (f a)
+2

All Articles