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