Michael Snoyman | 1 Oct 08:58 2013

Lifting IO actions into Applicatives

I'm wondering if anyone's run into this problem before, and if there's a common solution.

In Yesod, we have applicative forms (based originally on formlets). These forms are instances of Applicative, but not of Monad. Let's consider a situation where we want to get some user input to fill out a blog post datatype, which includes the current time:

data Blog = Blog Title UTCTime Contents

myBlogForm :: Form Blog
myBlogForm = Blog <$> titleForm <*> something <*> contentsForm

The question is: what goes in something? Its type has to be:

something :: Form UTCTime

Ideally, I'd call getCurrentTime. The question is: how do I lift that into a Form? Since Form is only an Applicative, not a Monad, I can't create a MonadIO instance. However, Form is in fact built on top of IO[1]. And it's possible to create a MonadTrans instance for Form, since it's entirely possible to lift actions from the underlying functor/monad into Form. So something can be written as:

something = lift $ liftIO getCurrentTime

This works, but is unintuitive. One solution would be to have an ApplicativeIO typeclass and then use liftIOA. My questions here are:

1. Has anyone else run into this issue?
2. Is there an existing solution out there?

Michael

_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe <at> haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe
John Lato | 1 Oct 09:21 2013
Picon

Re: Lifting IO actions into Applicatives

It's not a solution per se, but it seems to me that there's no need for the Monad superclass constraint on MonadIO.  If that were removed, we could just have

class LiftIO t where
    liftIO :: IO a -> t a

and it would Just Work.


On Tue, Oct 1, 2013 at 1:58 AM, Michael Snoyman <michael <at> snoyman.com> wrote:
I'm wondering if anyone's run into this problem before, and if there's a common solution.

In Yesod, we have applicative forms (based originally on formlets). These forms are instances of Applicative, but not of Monad. Let's consider a situation where we want to get some user input to fill out a blog post datatype, which includes the current time:

data Blog = Blog Title UTCTime Contents

myBlogForm :: Form Blog
myBlogForm = Blog <$> titleForm <*> something <*> contentsForm

The question is: what goes in something? Its type has to be:

something :: Form UTCTime

Ideally, I'd call getCurrentTime. The question is: how do I lift that into a Form? Since Form is only an Applicative, not a Monad, I can't create a MonadIO instance. However, Form is in fact built on top of IO[1]. And it's possible to create a MonadTrans instance for Form, since it's entirely possible to lift actions from the underlying functor/monad into Form. So something can be written as:

something = lift $ liftIO getCurrentTime

This works, but is unintuitive. One solution would be to have an ApplicativeIO typeclass and then use liftIOA. My questions here are:

1. Has anyone else run into this issue?
2. Is there an existing solution out there?

Michael


_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe <at> haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe <at> haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe
Niklas Haas | 1 Oct 09:29 2013
Picon

Re: Lifting IO actions into Applicatives

On Tue, 1 Oct 2013 02:21:13 -0500, John Lato <jwlato <at> gmail.com> wrote:
> It's not a solution per se, but it seems to me that there's no need for the
> Monad superclass constraint on MonadIO.  If that were removed, we could
> just have
> 
> class LiftIO t where
>     liftIO :: IO a -> t a
> 
> and it would Just Work.

One concern with this is that it's not exactly clear what the semantics
are on LiftIO (is liftIO a >> liftIO b equal to liftIO (a >> b) or not?)
and the interaction between LiftIO and Applicative/Monad would have to
be some sort of ugly ad-hoc law like we have with Bounded/Enum etc.

Furthermore, you might end up specifying a lot of ‘redundant’
constraints like (Monad m, LiftIO m) that way, just a thing to keep in
mind.
_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe <at> haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe
Jose A. Lopes | 1 Oct 09:42 2013
Picon

Re: Lifting IO actions into Applicatives

On Tue, Oct 01, 2013 at 09:29:00AM +0200, Niklas Haas wrote:
> On Tue, 1 Oct 2013 02:21:13 -0500, John Lato <jwlato <at> gmail.com> wrote:
> > It's not a solution per se, but it seems to me that there's no need for the
> > Monad superclass constraint on MonadIO.  If that were removed, we could
> > just have
> > 
> > class LiftIO t where
> >     liftIO :: IO a -> t a
> > 
> > and it would Just Work.
> 
> One concern with this is that it's not exactly clear what the semantics
> are on LiftIO (is liftIO a >> liftIO b equal to liftIO (a >> b) or not?)
> and the interaction between LiftIO and Applicative/Monad would have to
> be some sort of ugly ad-hoc law like we have with Bounded/Enum etc.

What is this 'ad-hoc law' you are talking about ?

> 
> Furthermore, you might end up specifying a lot of ‘redundant’
> constraints like (Monad m, LiftIO m) that way, just a thing to keep in
> mind.
> _______________________________________________
> Haskell-Cafe mailing list
> Haskell-Cafe <at> haskell.org
> http://www.haskell.org/mailman/listinfo/haskell-cafe

--

-- 
Jose Antonio Lopes
Ganeti Engineering
Google Germany GmbH
Dienerstr. 12, 80331, München

Registergericht und -nummer: Hamburg, HRB 86891
Sitz der Gesellschaft: Hamburg
Geschäftsführer: Graham Law, Christine Elizabeth Flores
Steuernummer: 48/725/00206
Umsatzsteueridentifikationsnummer: DE813741370
_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe <at> haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe
Tom Ellis | 1 Oct 10:20 2013
Picon

Re: Lifting IO actions into Applicatives

On Tue, Oct 01, 2013 at 09:29:00AM +0200, Niklas Haas wrote:
> On Tue, 1 Oct 2013 02:21:13 -0500, John Lato <jwlato <at> gmail.com> wrote:
> > It's not a solution per se, but it seems to me that there's no need for the
> > Monad superclass constraint on MonadIO.  If that were removed, we could
> > just have
> > 
> > class LiftIO t where
> >     liftIO :: IO a -> t a
> > 
> > and it would Just Work.
> 
> One concern with this is that it's not exactly clear what the semantics
> are on LiftIO (is liftIO a >> liftIO b equal to liftIO (a >> b) or not?)
> and the interaction between LiftIO and Applicative/Monad would have to
> be some sort of ugly ad-hoc law like we have with Bounded/Enum etc.

Shouldn't it be an *Applicative* constraint?

    class Applicative t => ApplicativeIO t where
        liftIO :: IO a -> t a

and require that

    liftIO (pure x) = pure x
    liftIO (f <*> x) = liftIO f <*> liftIO x

Seems like ApplicativeIO makes more sense than MonadIO, which is
unnecessarily restrictive.  With planned Functor/Applicative/Monad shuffle,
the former could completely replace the latter.

Tom
Roman Cheplyaka | 1 Oct 11:11 2013

Re: Lifting IO actions into Applicatives

* Tom Ellis <tom-lists-haskell-cafe-2013 <at> jaguarpaw.co.uk> [2013-10-01 09:20:23+0100]
> On Tue, Oct 01, 2013 at 09:29:00AM +0200, Niklas Haas wrote:
> > On Tue, 1 Oct 2013 02:21:13 -0500, John Lato <jwlato <at> gmail.com> wrote:
> > > It's not a solution per se, but it seems to me that there's no need for the
> > > Monad superclass constraint on MonadIO.  If that were removed, we could
> > > just have
> > > 
> > > class LiftIO t where
> > >     liftIO :: IO a -> t a
> > > 
> > > and it would Just Work.
> > 
> > One concern with this is that it's not exactly clear what the semantics
> > are on LiftIO (is liftIO a >> liftIO b equal to liftIO (a >> b) or not?)
> > and the interaction between LiftIO and Applicative/Monad would have to
> > be some sort of ugly ad-hoc law like we have with Bounded/Enum etc.
> 
> Shouldn't it be an *Applicative* constraint?
> 
>     class Applicative t => ApplicativeIO t where
>         liftIO :: IO a -> t a
> 
> and require that
> 
>     liftIO (pure x) = pure x
>     liftIO (f <*> x) = liftIO f <*> liftIO x
> 
> Seems like ApplicativeIO makes more sense than MonadIO, which is
> unnecessarily restrictive.  With planned Functor/Applicative/Monad shuffle,
> the former could completely replace the latter.

Agreed, this makes perfect sense. It simply says that liftIO is an
applicative homomorphism.

Roman
_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe <at> haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe
Tom Ellis | 1 Oct 11:47 2013
Picon

Re: Lifting IO actions into Applicatives

On Tue, Oct 01, 2013 at 12:11:23PM +0300, Roman Cheplyaka wrote:
> > Shouldn't it be an *Applicative* constraint?
> > 
> >     class Applicative t => ApplicativeIO t where
> >         liftIO :: IO a -> t a
> > 
> > and require that
> > 
> >     liftIO (pure x) = pure x
> >     liftIO (f <*> x) = liftIO f <*> liftIO x
> > 
> > Seems like ApplicativeIO makes more sense than MonadIO, which is
> > unnecessarily restrictive.  With planned Functor/Applicative/Monad shuffle,
> > the former could completely replace the latter.
> 
> Agreed, this makes perfect sense. It simply says that liftIO is an
> applicative homomorphism.

Indeed.  A related question is whether, when m and m' are monads, an
applicative homomorphism between m and m' is automatically a monad
homomorphism.  That seems important in determining if one typeclass is
actually enough.

In fact we could go crazy and define

    class Functor f => FunctorIO f where
        liftIO :: IO a -> f a

and require that

    liftIO . fmap f = fmap f . liftIO

i.e. essentially that liftIO is a natural transformation between IO and f. 
I don't know whether there are simpler sufficient conditions that allow one
to determine that such an instance is also an applicative and monad
morphism.

Tom
Dan Burton | 1 Oct 11:15 2013
Picon

Re: Lifting IO actions into Applicatives

From what you've said, it sounds like you can already write:

    serverSide :: IO a -> Form a

This seems elegant enough to me for your needs. Just encourage it as an idiom specific to Forms.

    myBlogForm = Blog <$> titleForm <*> serverSide getCurrentTime <*> contentsForm

Could you abstract `serverSide` out into a typeclass, such as ApplicativeIO? Sure. but why bother? The point is, you've got the specialization you need already.

-- Dan Burton


On Tue, Oct 1, 2013 at 1:20 AM, Tom Ellis <tom-lists-haskell-cafe-2013 <at> jaguarpaw.co.uk> wrote:
On Tue, Oct 01, 2013 at 09:29:00AM +0200, Niklas Haas wrote:
> On Tue, 1 Oct 2013 02:21:13 -0500, John Lato <jwlato <at> gmail.com> wrote:
> > It's not a solution per se, but it seems to me that there's no need for the
> > Monad superclass constraint on MonadIO.  If that were removed, we could
> > just have
> >
> > class LiftIO t where
> >     liftIO :: IO a -> t a
> >
> > and it would Just Work.
>
> One concern with this is that it's not exactly clear what the semantics
> are on LiftIO (is liftIO a >> liftIO b equal to liftIO (a >> b) or not?)
> and the interaction between LiftIO and Applicative/Monad would have to
> be some sort of ugly ad-hoc law like we have with Bounded/Enum etc.

Shouldn't it be an *Applicative* constraint?

    class Applicative t => ApplicativeIO t where
        liftIO :: IO a -> t a

and require that

    liftIO (pure x) = pure x
    liftIO (f <*> x) = liftIO f <*> liftIO x

Seems like ApplicativeIO makes more sense than MonadIO, which is
unnecessarily restrictive.  With planned Functor/Applicative/Monad shuffle,
the former could completely replace the latter.

Tom
_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe <at> haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe

_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe <at> haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe
Yitzchak Gale | 1 Oct 14:27 2013

Re: Lifting IO actions into Applicatives

Dan Burton wrote:
> From what you've said, it sounds like you can already write:
>
>     serverSide :: IO a -> Form a
>
> This seems elegant enough to me for your needs. Just encourage it as an
> idiom specific to Forms.
>
>     myBlogForm = Blog <$> titleForm <*> serverSide getCurrentTime <*>
> contentsForm
>
> Could you abstract `serverSide` out into a typeclass, such as ApplicativeIO?
> Sure. but why bother? The point is, you've got the specialization you need
> already.

In my opinion, this is the nicest answer to the original question
about yesod forms. But the more general question that it led to
is an interesting and important one.

-Yitz
Michael Snoyman | 1 Oct 18:02 2013

Re: Lifting IO actions into Applicatives




On Tue, Oct 1, 2013 at 12:15 PM, Dan Burton <danburton.email <at> gmail.com> wrote:
From what you've said, it sounds like you can already write:

    serverSide :: IO a -> Form a

This seems elegant enough to me for your needs. Just encourage it as an idiom specific to Forms.

    myBlogForm = Blog <$> titleForm <*> serverSide getCurrentTime <*> contentsForm

Could you abstract `serverSide` out into a typeclass, such as ApplicativeIO? Sure. but why bother? The point is, you've got the specialization you need already.



Yes, I agree that to simply solve the problem in yesod-form, this would be a great solution. But as to "why bother" with ApplicativeIO: my point in sending this email was to see if other people have been bothered by this, and if it's therefore worth coming up with a general purpose solution. If there's no real interest in it, I don't see a need to create such a general solution. On the other hand, if people think this is worth a general ApplicativeIO class, I'd be happy to use that instead of defining an ad-hoc function in yesod-form.

Thanks to everyone for this great discussion, I'm thoroughly enjoying following it.

Michael 
_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe <at> haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe
Yitzchak Gale | 1 Oct 14:17 2013

Re: Lifting IO actions into Applicatives

Tom Ellis wrote:
> Shouldn't it be an *Applicative* constraint?
>
>     class Applicative t => ApplicativeIO t where
>         liftIO :: IO a -> t a
>
> and require that
>
>     liftIO (pure x) = pure x
>     liftIO (f <*> x) = liftIO f <*> liftIO x
>
> Seems like ApplicativeIO makes more sense than MonadIO, which is
> unnecessarily restrictive.  With planned Functor/Applicative/Monad shuffle,
> the former could completely replace the latter.

In fact, it even makes sense to define it as FunctorIO, with the only laws
being that liftIO commutes with fmap and preserves id, i.e., that it is
a natural transformation. (Those laws are also needed for ApplicativeIO
and MonadIO.)

Since Haskell is not dependently typed and we specify laws only as
human-readable comments, should we define only FunctorIO and
then just specify in the comments the additional laws that should
be satisfied for Applicative and Monad? Or should we have equivalent
definitions that differ only in the laws that are expected to be satisfied?
Or should the different definitions have different superclass constraints?

Let's get it right this time and not create yet another
Functor/Applicative/Monad mess.

Thanks,
Yitz
Tom Ellis | 1 Oct 14:35 2013
Picon

Re: Lifting IO actions into Applicatives

On Tue, Oct 01, 2013 at 03:17:40PM +0300, Yitzchak Gale wrote:
> Tom Ellis wrote:
> > Shouldn't it be an *Applicative* constraint?
> >
> >     class Applicative t => ApplicativeIO t where
> >         liftIO :: IO a -> t a
> >
> > and require that
> >
> >     liftIO (pure x) = pure x
> >     liftIO (f <*> x) = liftIO f <*> liftIO x
> >
> > Seems like ApplicativeIO makes more sense than MonadIO, which is
> > unnecessarily restrictive.  With planned Functor/Applicative/Monad shuffle,
> > the former could completely replace the latter.
> 
> In fact, it even makes sense to define it as FunctorIO, with the only laws
> being that liftIO commutes with fmap and preserves id, i.e., that it is
> a natural transformation. (Those laws are also needed for ApplicativeIO
> and MonadIO.)

I think that law follows automatically from parametricity, doesn't it?

> Since Haskell is not dependently typed and we specify laws only as
> human-readable comments, should we define only FunctorIO and
> then just specify in the comments the additional laws that should
> be satisfied for Applicative and Monad? Or should we have equivalent
> definitions that differ only in the laws that are expected to be satisfied?
> Or should the different definitions have different superclass constraints?

In tackling such questions I think it would be useful to know how many such
instances there can be.  Can there be more than one morphism between two
monads?  Between two applicatives?  I would guess there are plenty of
examples of functors with more than one functor morphism (natural
transformation) between them.

Perhaps these questions are easy, but I don't know how to approach them.

Tom
John Wiegley | 1 Oct 20:00 2013

Re: Lifting IO actions into Applicatives

>>>>> Yitzchak Gale <gale <at> sefer.org> writes:

> In fact, it even makes sense to define it as FunctorIO, with the only laws
> being that liftIO commutes with fmap and preserves id, i.e., that it is a
> natural transformation. (Those laws are also needed for ApplicativeIO and
> MonadIO.)

Given that we are moving toward Applicative (and thus Functor) as a superclass
of Monad, why not just solve the MonadIO problem and similar type classes with
natural transformations?  It requires 3 extensions, but these are extensions I
believe should become part of Haskell anyway:

    {-# LANGUAGE FlexibleInstances #-}
    {-# LANGUAGE MultiParamTypeClasses #-}
    {-# LANGUAGE RankNTypes #-}

    module NatTrans where

    import Control.Monad.IO.Class
    import Control.Monad.Trans.Maybe

    class (Functor s, Functor t) => NatTrans s t where
        nmap :: forall a. s a -> t a
        -- Such that: nmap . fmap f = fmap f . nmap

    -- In 7.10, this Functor constraint becomes redundant    
    instance (Functor m, MonadIO m) => NatTrans IO m where
        nmap = liftIO

    main :: IO ()
    main = void $ runMaybeT $ nmap $ print (10 :: Int)

Now if I have a functor of one kind and need another, I reach for nmap in the
same way that I reach for fmap to transform the mapped type.

--

-- 
John Wiegley
FP Complete                         Haskell tools, training and consulting
http://fpcomplete.com               johnw on #haskell/irc.freenode.net
Dan Burton | 1 Oct 20:41 2013
Picon

Re: Lifting IO actions into Applicatives

Interesting. It's similar in spirit to basically a safe Coerce typeclass, but for * -> * types.

    class Coerce a b where
      coerce :: a -> b

    class Coerce1 f g where
      coerce1 :: f a -> g a



-- Dan Burton


On Tue, Oct 1, 2013 at 11:00 AM, John Wiegley <johnw <at> fpcomplete.com> wrote:
>>>>> Yitzchak Gale <gale <at> sefer.org> writes:

> In fact, it even makes sense to define it as FunctorIO, with the only laws
> being that liftIO commutes with fmap and preserves id, i.e., that it is a
> natural transformation. (Those laws are also needed for ApplicativeIO and
> MonadIO.)

Given that we are moving toward Applicative (and thus Functor) as a superclass
of Monad, why not just solve the MonadIO problem and similar type classes with
natural transformations?  It requires 3 extensions, but these are extensions I
believe should become part of Haskell anyway:

    {-# LANGUAGE FlexibleInstances #-}
    {-# LANGUAGE MultiParamTypeClasses #-}
    {-# LANGUAGE RankNTypes #-}

    module NatTrans where

    import Control.Monad.IO.Class
    import Control.Monad.Trans.Maybe

    class (Functor s, Functor t) => NatTrans s t where
        nmap :: forall a. s a -> t a
        -- Such that: nmap . fmap f = fmap f . nmap

    -- In 7.10, this Functor constraint becomes redundant
    instance (Functor m, MonadIO m) => NatTrans IO m where
        nmap = liftIO

    main :: IO ()
    main = void $ runMaybeT $ nmap $ print (10 :: Int)

Now if I have a functor of one kind and need another, I reach for nmap in the
same way that I reach for fmap to transform the mapped type.

--
John Wiegley
FP Complete                         Haskell tools, training and consulting
http://fpcomplete.com               johnw on #haskell/irc.freenode.net
_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe <at> haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe

_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe <at> haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe
Daniil Frumin | 7 Oct 17:57 2013
Picon

Re: Lifting IO actions into Applicatives

Isn't it the case that there could be more than one natural transformation between functors?


On Tue, Oct 1, 2013 at 10:00 PM, John Wiegley <johnw <at> fpcomplete.com> wrote:
>>>>> Yitzchak Gale <gale <at> sefer.org> writes:

> In fact, it even makes sense to define it as FunctorIO, with the only laws
> being that liftIO commutes with fmap and preserves id, i.e., that it is a
> natural transformation. (Those laws are also needed for ApplicativeIO and
> MonadIO.)

Given that we are moving toward Applicative (and thus Functor) as a superclass
of Monad, why not just solve the MonadIO problem and similar type classes with
natural transformations?  It requires 3 extensions, but these are extensions I
believe should become part of Haskell anyway:

    {-# LANGUAGE FlexibleInstances #-}
    {-# LANGUAGE MultiParamTypeClasses #-}
    {-# LANGUAGE RankNTypes #-}

    module NatTrans where

    import Control.Monad.IO.Class
    import Control.Monad.Trans.Maybe

    class (Functor s, Functor t) => NatTrans s t where
        nmap :: forall a. s a -> t a
        -- Such that: nmap . fmap f = fmap f . nmap

    -- In 7.10, this Functor constraint becomes redundant
    instance (Functor m, MonadIO m) => NatTrans IO m where
        nmap = liftIO

    main :: IO ()
    main = void $ runMaybeT $ nmap $ print (10 :: Int)

Now if I have a functor of one kind and need another, I reach for nmap in the
same way that I reach for fmap to transform the mapped type.

--
John Wiegley
FP Complete                         Haskell tools, training and consulting
http://fpcomplete.com               johnw on #haskell/irc.freenode.net
_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe <at> haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe



--
Sincerely yours,
-- Daniil
_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe <at> haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe
Tom Ellis | 7 Oct 18:04 2013
Picon

Re: Lifting IO actions into Applicatives

On Mon, Oct 07, 2013 at 07:57:23PM +0400, Daniil Frumin wrote:
> Isn't it the case that there could be more than one natural transformation
> between functors?

Definitely.  In addition rwbarton responded to my challenge by finding two
different applicative morphisms between the same applicative, one which
extends to a monad morphism and one which does not:

    http://www.reddit.com/r/haskell/comments/1ni8r6/should_it_be_monadio_applicativeio_functorio_or/ccjodj5

Tom
John Wiegley | 7 Oct 18:43 2013

Re: Lifting IO actions into Applicatives

>>>>> Daniil Frumin <difrumin <at> gmail.com> writes:

> Isn't it the case that there could be more than one natural transformation
> between functors?

Yes, I imagine there would have to be some newtype wrappers to distinguish in
those cases.

--

-- 
John Wiegley
FP Complete                         Haskell tools, training and consulting
http://fpcomplete.com               johnw on #haskell/irc.freenode.net
Alexey Uimanov | 1 Oct 09:24 2013
Picon

Re: Lifting IO actions into Applicatives

Maybe this is needed new typeclass ApplicativeTrans?


2013/10/1 Michael Snoyman <michael <at> snoyman.com>
I'm wondering if anyone's run into this problem before, and if there's a common solution.

In Yesod, we have applicative forms (based originally on formlets). These forms are instances of Applicative, but not of Monad. Let's consider a situation where we want to get some user input to fill out a blog post datatype, which includes the current time:

data Blog = Blog Title UTCTime Contents

myBlogForm :: Form Blog
myBlogForm = Blog <$> titleForm <*> something <*> contentsForm

The question is: what goes in something? Its type has to be:

something :: Form UTCTime

Ideally, I'd call getCurrentTime. The question is: how do I lift that into a Form? Since Form is only an Applicative, not a Monad, I can't create a MonadIO instance. However, Form is in fact built on top of IO[1]. And it's possible to create a MonadTrans instance for Form, since it's entirely possible to lift actions from the underlying functor/monad into Form. So something can be written as:

something = lift $ liftIO getCurrentTime

This works, but is unintuitive. One solution would be to have an ApplicativeIO typeclass and then use liftIOA. My questions here are:

1. Has anyone else run into this issue?
2. Is there an existing solution out there?

Michael


_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe <at> haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe <at> haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe
Michael Snoyman | 1 Oct 18:05 2013

Re: Lifting IO actions into Applicatives




On Tue, Oct 1, 2013 at 10:24 AM, Alexey Uimanov <s9gf4ult <at> gmail.com> wrote:
Maybe this is needed new typeclass ApplicativeTrans?



There's actually no problem with defining a MonadTrans instance for non-monads. Obviously this can't follow the laws directly (since they're defined in terms of monadic bind and return), but I think we could probably state Applicative versions of those laws (assuming I haven't made a stupid mistake):

lift . pure = pure
lift (x <*> y) = lift x <*> lift y

Michael
 
2013/10/1 Michael Snoyman <michael <at> snoyman.com>
I'm wondering if anyone's run into this problem before, and if there's a common solution.

In Yesod, we have applicative forms (based originally on formlets). These forms are instances of Applicative, but not of Monad. Let's consider a situation where we want to get some user input to fill out a blog post datatype, which includes the current time:

data Blog = Blog Title UTCTime Contents

myBlogForm :: Form Blog
myBlogForm = Blog <$> titleForm <*> something <*> contentsForm

The question is: what goes in something? Its type has to be:

something :: Form UTCTime

Ideally, I'd call getCurrentTime. The question is: how do I lift that into a Form? Since Form is only an Applicative, not a Monad, I can't create a MonadIO instance. However, Form is in fact built on top of IO[1]. And it's possible to create a MonadTrans instance for Form, since it's entirely possible to lift actions from the underlying functor/monad into Form. So something can be written as:

something = lift $ liftIO getCurrentTime

This works, but is unintuitive. One solution would be to have an ApplicativeIO typeclass and then use liftIOA. My questions here are:

1. Has anyone else run into this issue?
2. Is there an existing solution out there?

Michael


_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe <at> haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe



_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe <at> haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe <at> haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe
Alberto G. Corona | 1 Oct 19:12 2013
Picon

Re: Lifting IO actions into Applicatives

In MFow there is a Monad instance for formlets that make a lot of sense. Apart from using liftIO inside an applicative formlets


it can do it that way also:

myBlogForm = do
     t <- liftIO getTime
     Blog <$> titleForm <*> return t <*> contentsForm

Which may look contrived, but instead of using return t, we can display for the user something interesting in that place.
There are other  dynamic things, like asking different questions depending on previous responses thanks to the monad instance :



2013/10/1 Michael Snoyman <michael <at> snoyman.com>



On Tue, Oct 1, 2013 at 10:24 AM, Alexey Uimanov <s9gf4ult <at> gmail.com> wrote:
Maybe this is needed new typeclass ApplicativeTrans?



There's actually no problem with defining a MonadTrans instance for non-monads. Obviously this can't follow the laws directly (since they're defined in terms of monadic bind and return), but I think we could probably state Applicative versions of those laws (assuming I haven't made a stupid mistake):

lift . pure = pure
lift (x <*> y) = lift x <*> lift y

Michael
 
2013/10/1 Michael Snoyman <michael <at> snoyman.com>
I'm wondering if anyone's run into this problem before, and if there's a common solution.

In Yesod, we have applicative forms (based originally on formlets). These forms are instances of Applicative, but not of Monad. Let's consider a situation where we want to get some user input to fill out a blog post datatype, which includes the current time:

data Blog = Blog Title UTCTime Contents

myBlogForm :: Form Blog
myBlogForm = Blog <$> titleForm <*> something <*> contentsForm

The question is: what goes in something? Its type has to be:

something :: Form UTCTime

Ideally, I'd call getCurrentTime. The question is: how do I lift that into a Form? Since Form is only an Applicative, not a Monad, I can't create a MonadIO instance. However, Form is in fact built on top of IO[1]. And it's possible to create a MonadTrans instance for Form, since it's entirely possible to lift actions from the underlying functor/monad into Form. So something can be written as:

something = lift $ liftIO getCurrentTime

This works, but is unintuitive. One solution would be to have an ApplicativeIO typeclass and then use liftIOA. My questions here are:

1. Has anyone else run into this issue?
2. Is there an existing solution out there?

Michael


_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe <at> haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe



_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe <at> haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe



_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe <at> haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe




--
Alberto.
_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe <at> haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe
MigMit | 1 Oct 09:25 2013
Picon

Re: Lifting IO actions into Applicatives

What about (Compose Form IO) Blog type? Form is Applicative, IO — the same, their composition should be Applicative as well (one good thing about Applicatives — they really compose). Take a look at Control.Compose module.

Отправлено с iPad

01 окт. 2013 г., в 10:58, Michael Snoyman <michael <at> snoyman.com> написал(а):

I'm wondering if anyone's run into this problem before, and if there's a common solution.

In Yesod, we have applicative forms (based originally on formlets). These forms are instances of Applicative, but not of Monad. Let's consider a situation where we want to get some user input to fill out a blog post datatype, which includes the current time:

data Blog = Blog Title UTCTime Contents

myBlogForm :: Form Blog
myBlogForm = Blog <$> titleForm <*> something <*> contentsForm

The question is: what goes in something? Its type has to be:

something :: Form UTCTime

Ideally, I'd call getCurrentTime. The question is: how do I lift that into a Form? Since Form is only an Applicative, not a Monad, I can't create a MonadIO instance. However, Form is in fact built on top of IO[1]. And it's possible to create a MonadTrans instance for Form, since it's entirely possible to lift actions from the underlying functor/monad into Form. So something can be written as:

something = lift $ liftIO getCurrentTime

This works, but is unintuitive. One solution would be to have an ApplicativeIO typeclass and then use liftIOA. My questions here are:

1. Has anyone else run into this issue?
2. Is there an existing solution out there?

Michael

_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe <at> haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe
_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe <at> haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe
Oliver Charles | 1 Oct 10:15 2013
Picon

Re: Lifting IO actions into Applicatives

On 10/01/2013 07:58 AM, Michael Snoyman wrote:
> I'm wondering if anyone's run into this problem before, and if there's a
> common solution.
> 
> In Yesod, we have applicative forms (based originally on formlets).
> These forms are instances of Applicative, but not of Monad. Let's
> consider a situation where we want to get some user input to fill out a
> blog post datatype, which includes the current time:
> 
> data Blog = Blog Title UTCTime Contents
> 
> myBlogForm :: Form Blog
> myBlogForm = Blog <$> titleForm <*> something <*> contentsForm
> 
> The question is: what goes in something? Its type has to be:
> 
> something :: Form UTCTime
> 
> Ideally, I'd call getCurrentTime. The question is: how do I lift that
> into a Form? Since Form is only an Applicative, not a Monad, I can't
> create a MonadIO instance. However, Form is in fact built on top of
> IO[1]. And it's possible to create a MonadTrans instance for Form, since
> it's entirely possible to lift actions from the underlying functor/monad
> into Form. So something can be written as:
> 
> something = lift $ liftIO getCurrentTime

Is it really necessary to have a type class to do this? You can always
just introduce 'io :: IO a -> Form a' to lift IO actions into a form.
Then you just have:

myBlogForm = Blog <$> titleForm <*> io getCurrentTime <*> contentsForm

In digestive-functors, we have the base monad in the type of the form
itself, so we provide 'monadic' which goes from
m (Form m a) -> Form m a (hand-waving as there are actually other type
constraints). You might get more power by following in those steps, and
having the aforementioned 'io' function actually be:

io :: IO (Form a) -> Form a

- ocharles

_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe <at> haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe
Alexander Solla | 1 Oct 19:22 2013
Picon

Re: Lifting IO actions into Applicatives


On Mon, Sep 30, 2013 at 11:58 PM, Michael Snoyman <michael <at> snoyman.com> wrote:
I'm wondering if anyone's run into this problem before, and if there's a common solution.


I ran into it, asked about it on SO, and followed your advice. :)

_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe <at> haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe

Gmane