Lift data from IO to Validation

Hi - I am not an experienced Haskell programmer and would like to have some help with the following problem .. I am trying to validate a bunch of inputs and found the package Data.Validation. I am also using Data.Time for date and time. I have a function like this .. validateOpenDate :: ZonedTime -> Validation [String] ZonedTime It's supposed to validate a date for which I need to fetch the current date and time. I can do that with getZonedTime :: IO ZonedTime. I want to check if the current time is less than the date time I pass to the function and return an appropriate Validation. The question is how do I lift the result from IO into the Validation ? Or is there any alternative strategy that I should consider for this validation ? I have a number of other validations which follow the same strategy but don't have the IO. My final goal is to be able to compose all these validations applicatively to prepare a final ADT in a smart constructor. Any help will be appreciated .. regards. -- Debasish Ghosh

On Sat, Jan 04, 2020 at 08:28:50PM +0530, Debasish Ghosh wrote:
validateOpenDate :: ZonedTime -> Validation [String] ZonedTime
It's supposed to validate a date for which I need to fetch the current date and time. I can do that with getZonedTime :: IO ZonedTime. I want to check if the current time is less than the date time I pass to the function and return an appropriate Validation.
How about validateNow = do zonedTime <- getZonedTime return (validateOpenDate zonedTime)

On Sat, Jan 04, 2020 at 08:28:50PM +0530, Debasish Ghosh wrote:
I am trying to validate a bunch of inputs and found the package Data.Validation. I am also using Data.Time for date and time. I have a function like this.
validateOpenDate :: ZonedTime -> Validation [String] ZonedTime
It's supposed to validate a date for which I need to fetch the current date and time. I can do that with getZonedTime :: IO ZonedTime. I want to check if the current time is less than the date time I pass to the function and return an appropriate Validation.
This function is not pure. It needs an external input that affects its output. Therefore, the honest type of this function is either: -- | Validate date relative to current time validateOpenDate :: ZonedTime -> IO (Validation [String] ZonedTime) or (with the caller doing the time lookup): -- | Validate date relative to supplied time validateOpenDate :: ZonedTime -> ZonedTime -> Validation [String] ZonedTime The "supplied time could be generalized to an "Environment" that carries whatever context information might be needed: type Env = Env { curTime :: !ZonedTime } With all the validation functions now: validateOpenDate :: ZonedTime -> Reader Env (Validation [String] ZonedTime) validateOpenData inputDate = do now <- asks curTime if inputDate > now then ... else ... and then import Control.Monad.Reader main :: IO () main = do env <- Env <$> getZonedTime flip runReader env $ do -- computations doing validation relative to the environment
The question is how do I lift the result from IO into the Validation?
The only way to do that without changing the output type is to lie, and use "unsafePerformIO" to extract the date inside a pure function. This is not recommended.
Or is there any alternative strategy that I should consider for this validation ? I have a number of other validations which follow the same strategy but don't have the IO. My final goal is to be able to compose all these validations applicatively to prepare a final ADT in a smart constructor.
You should be able "compose" the validations in the context of an environment. Either Monadically, or Applicatively. -- Viktor.

Thanks for all the suggestions .. Here's an example of a validation
function with Reader Env ..
validateOpenDate :: ZonedTime -> Reader Env (Validation [String] ZonedTime)
validateOpenDate openDate = do
now <- asks curTime
if zonedTimeToUTC openDate > zonedTimeToUTC now
then return $ Failure ["Account open date cannot be in the future"]
else return $ Success openDate
I have a few such functions and I wire them together to form a smart
constructor that builds an ADT ..
makeAccount :: String -> String -> ZonedTime -> IO (Validation [String]
Account)
makeAccount no name openDate = do
env <- Env <$> getZonedTime
flip runReader env $ do
validAccountNo <- validateAccountNo no
validAccountName <- validateAccountName name
validOpeningDate <- validateOpenDate openDate
return $ return $ Account <$> validAccountNo <*> validAccountName <*>
validOpeningDate
Does this look like an idiomatic implementation ? Is there any scope to
make things better ? I compose applicatively as I need to accumulate all
validation errors. And also Validation does not have a Monad ..
regards.
On Sat, Jan 4, 2020 at 9:20 PM Viktor Dukhovni
On Sat, Jan 04, 2020 at 08:28:50PM +0530, Debasish Ghosh wrote:
I am trying to validate a bunch of inputs and found the package Data.Validation. I am also using Data.Time for date and time. I have a function like this.
validateOpenDate :: ZonedTime -> Validation [String] ZonedTime
It's supposed to validate a date for which I need to fetch the current date and time. I can do that with getZonedTime :: IO ZonedTime. I want to check if the current time is less than the date time I pass to the function and return an appropriate Validation.
This function is not pure. It needs an external input that affects its output. Therefore, the honest type of this function is either:
-- | Validate date relative to current time validateOpenDate :: ZonedTime -> IO (Validation [String] ZonedTime)
or (with the caller doing the time lookup):
-- | Validate date relative to supplied time validateOpenDate :: ZonedTime -> ZonedTime -> Validation [String] ZonedTime
The "supplied time could be generalized to an "Environment" that carries whatever context information might be needed:
type Env = Env { curTime :: !ZonedTime }
With all the validation functions now:
validateOpenDate :: ZonedTime -> Reader Env (Validation [String] ZonedTime) validateOpenData inputDate = do now <- asks curTime if inputDate > now then ... else ...
and then
import Control.Monad.Reader
main :: IO () main = do env <- Env <$> getZonedTime flip runReader env $ do -- computations doing validation relative to the environment
The question is how do I lift the result from IO into the Validation?
The only way to do that without changing the output type is to lie, and use "unsafePerformIO" to extract the date inside a pure function. This is not recommended.
Or is there any alternative strategy that I should consider for this validation ? I have a number of other validations which follow the same strategy but don't have the IO. My final goal is to be able to compose all these validations applicatively to prepare a final ADT in a smart constructor.
You should be able "compose" the validations in the context of an environment. Either Monadically, or Applicatively.
-- Viktor. _______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.
-- Debasish Ghosh

You might want to check out https://hackage.haskell.org/package/monad-validate https://hackage.haskell.org/package/monad-validate, which provides a monad transformer version of a Validation-like type. You can stack it on top of IO and do whatever you want there. Errors are collected from multiple branches as long as you use applicative operations where possible, so you probably want to use ApplicativeDo. The monad laws are satisfied via a relaxed notion of equality; see the documentation for more info. Disclaimer: I am the author of monad-validate. Alexis
On Jan 4, 2020, at 08:58, Debasish Ghosh
wrote: Hi -
I am not an experienced Haskell programmer and would like to have some help with the following problem ..
I am trying to validate a bunch of inputs and found the package Data.Validation. I am also using Data.Time for date and time. I have a function like this ..
validateOpenDate :: ZonedTime -> Validation [String] ZonedTime
It's supposed to validate a date for which I need to fetch the current date and time. I can do that with getZonedTime :: IO ZonedTime. I want to check if the current time is less than the date time I pass to the function and return an appropriate Validation.
The question is how do I lift the result from IO into the Validation ? Or is there any alternative strategy that I should consider for this validation ? I have a number of other validations which follow the same strategy but don't have the IO. My final goal is to be able to compose all these validations applicatively to prepare a final ADT in a smart constructor.
Any help will be appreciated ..
regards.
-- Debasish Ghosh

Thanks for the pointer .. the documentation
https://hackage.haskell.org/package/monad-validate-1.2.0.0/docs/Control-Mona...
looks
awesome.
regards.
On Sun, Jan 5, 2020 at 1:00 AM Alexis King
You might want to check out https://hackage.haskell.org/package/monad-validate, which provides a monad transformer version of a Validation-like type. You can stack it on top of IO and do whatever you want there. Errors are collected from multiple branches as long as you use applicative operations where possible, so you probably want to use ApplicativeDo. The monad laws are satisfied via a relaxed notion of equality; see the documentation for more info.
Disclaimer: I am the author of monad-validate.
Alexis
On Jan 4, 2020, at 08:58, Debasish Ghosh
wrote: Hi -
I am not an experienced Haskell programmer and would like to have some help with the following problem ..
I am trying to validate a bunch of inputs and found the package Data.Validation. I am also using Data.Time for date and time. I have a function like this ..
validateOpenDate :: ZonedTime -> Validation [String] ZonedTime
It's supposed to validate a date for which I need to fetch the current date and time. I can do that with getZonedTime :: IO ZonedTime. I want to check if the current time is less than the date time I pass to the function and return an appropriate Validation.
The question is how do I lift the result from IO into the Validation ? Or is there any alternative strategy that I should consider for this validation ? I have a number of other validations which follow the same strategy but don't have the IO. My final goal is to be able to compose all these validations applicatively to prepare a final ADT in a smart constructor.
Any help will be appreciated ..
regards.
-- Debasish Ghosh
-- Debasish Ghosh http://manning.com/ghosh2 http://manning.com/ghosh Twttr: @debasishg Blog: http://debasishg.blogspot.com Code: http://github.com/debasishg

The documentation of monad-validate is indeed great. I didn't know about
this package before. I will add it to my list of nice Haskell libraries.
Cheers,
Daniel
Am Sa., 4. Jan. 2020 um 20:31 Uhr schrieb Alexis King : You might want to check out
https://hackage.haskell.org/package/monad-validate, which provides a
monad transformer version of a Validation-like type. You can stack it on
top of IO and do whatever you want there. Errors are collected from
multiple branches as long as you use applicative operations where possible,
so you probably want to use ApplicativeDo. The monad laws are satisfied via
a relaxed notion of equality; see the documentation for more info. Disclaimer: I am the author of monad-validate. Alexis On Jan 4, 2020, at 08:58, Debasish Ghosh Hi - I am not an experienced Haskell programmer and would like to have some
help with the following problem .. I am trying to validate a bunch of inputs and found the package
Data.Validation. I am also using Data.Time for date and time. I have a
function like this .. validateOpenDate :: ZonedTime -> Validation [String] ZonedTime It's supposed to validate a date for which I need to fetch the current
date and time. I can do that with getZonedTime :: IO ZonedTime. I want to
check if the current time is less than the date time I pass to the function
and return an appropriate Validation. The question is how do I lift the result from IO into the Validation ? Or
is there any alternative strategy that I should consider for this
validation ? I have a number of other validations which follow the same
strategy but don't have the IO. My final goal is to be able to compose all
these validations applicatively to prepare a final ADT in a smart
constructor. Any help will be appreciated .. regards. --
Debasish Ghosh _______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.
participants (5)
-
Alexis King
-
Daniel Díaz Casanueva
-
Debasish Ghosh
-
Tom Ellis
-
Viktor Dukhovni