I tried to validate the construction of a Record
with Applicatives
and the Either Monad
. It works fine. But I can't see all Error Messages. Only the first is visible because the Right
Path of the Either Monad
ignores them.
Here is my code:
import Data.Either (either)
import Text.Printf (printf)
data Record = Record
{ fieldA :: String
, fieldB :: String
, fieldC :: String
} deriving (Show, Eq)
type Err = String
setField :: String -> String -> Either Err String
setField field value
| length value > 0 = Right value
| otherwise = Left $ printf "value for field %s is to short" field
setFieldA :: String -> Either Err String
setFieldA = setField "fieldA"
setFieldB :: String -> Either Err String
setFieldB = setField "fieldB"
setFieldC :: String -> Either Err String
setFieldC = setField "fieldC"
makeRecord :: Either Err Record
makeRecord = Record
<$> setField "fieldA" "valueA"
<*> setField "fieldB" "valueB"
<*> setField "fieldC" "valueC"
makeRecord' :: Either Err Record
makeRecord' = Record
<$> setFieldA "valueA"
<*> setFieldB "valueB"
<*> setFieldC "valueC"
recordFromEither :: Either Err Record -> Maybe Record
recordFromEither r =
case r of
Right v -> Just $ v
Left _ -> Nothing
main :: IO ()
main = putStrLn $ output
where
output = case makeRecord of
Right v -> show v
Left err -> show err
main' :: IO ()
main' = putStrLn $ either id show makeRecord'
My question is how can I keep and display all error messages. Maybe with the State Monad?
That's because of the way the Either
Applicative
instance works. What you can do is to wrap Either
in a newtype
:
newtype Validation e r = Validation (Either e r) deriving (Eq, Show, Functor)
Then give it another Applicative
instance:
instance Monoid m => Applicative (Validation m) where
pure = Validation . pure
Validation (Left x) <*> Validation (Left y) = Validation (Left (mappend x y))
Validation f <*> Validation r = Validation (f <*> r)
You can now use <$>
and <*>
to compose a Validation [Err] Record
result. See my article on Applicative validation for more details.