Hi folks,
I have two data types that differ in only their Applicative
instance, just to play around with a data type that does not accumulate errors and one that does.
The source code can be found here, but for the purposes of this post, what I would like to focus on is the following two functions:
validateResult :: RawData -> Result [CustomError] ValidData
validateResult RawData {..} =
ValidData
<$> expect "fieldOne" fieldOne
<*> expect "fieldTwo" fieldTwo
<*> expect "fieldThree" fieldThree
where
expect :: String -> Maybe a -> Result [CustomError] a
expect field Nothing = Result . Left $ [CustomError field]
expect field (Just a) = Result $ Right a
validateOperation :: RawData -> Operation [CustomError] ValidData
validateOperation RawData {..} =
ValidData
<$> expect "fieldOne" fieldOne
<*> expect "fieldTwo" fieldTwo
<*> expect "fieldThree" fieldThree
where
expect :: String -> Maybe a -> Operation [CustomError] a
expect field Nothing = Operation . Left $ [CustomError field]
expect field (Just a) = Operation $ Right a
The two functions are the same. The only thing that differs is the data constructor used to create the success and failure conditions in expect
. Therefore, I imagine that there is a way to create a function such as:
validate :: (Applicative v, Validate v) => RawData -> v ValidData
validate RawData {..} =
ValidData
<$> expect "fieldOne" fieldOne
<*> expect "fieldTwo" fieldTwo
<*> expect "fieldThree" fieldThree
where
expect field Nothing = refute [CustomError field]
expect field (Just a) = success a
I have tried to do this (as you can see in the commented-out code in the source file), but it leads to a host of type errors, and I was wondering if someone could point me in the right direction.
I understand that this is a very open-ended question, but I don’t know how to ask it in a more direct manner.