[Haskell-cafe] Lift data from IO to Validation

Viktor Dukhovni ietf-dane at dukhovni.org
Sat Jan 4 15:50:22 UTC 2020


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.


More information about the Haskell-Cafe mailing list