AMP - how do you motivate this in teaching?

Because of AMP, I have to rewrite slides and example code for my lectures, and I don't like it. In fact I probably won't do it, and will advise students to return to ghc-7.8 - but then, how does that look? Really, my answer to [1] 3.5 Beginner friendliness How often did you say ... "A Monad is always an Applicative" is: never. (for "is a Functor" - often. In fact, always) Now, I don't want to bring on another general discussion of AMP - instead I'd like to hear from people who use monads in teaching (e.g., to define semantic domains) about how they sell "Applicative m =>" to their students. (The intersection of AMPers and teachers is non-empty?) - Johannes [1] https://wiki.haskell.org/Functor-Applicative-Monad_Proposal

I have had to work around AMP not existing since 2006 in teaching. Thank goodness it is finally here and my students are no longer confused. That's how. On Fri, Nov 20, 2015 at 7:27 AM, Johannes Waldmann < johannes.waldmann@htwk-leipzig.de> wrote:
Because of AMP, I have to rewrite slides and example code for my lectures, and I don't like it.
In fact I probably won't do it, and will advise students to return to ghc-7.8 - but then, how does that look?
Really, my answer to
[1] 3.5 Beginner friendliness How often did you say ... "A Monad is always an Applicative"
is: never. (for "is a Functor" - often. In fact, always)
Now, I don't want to bring on another general discussion of AMP - instead I'd like to hear from people who use monads in teaching (e.g., to define semantic domains) about how they sell "Applicative m =>" to their students. (The intersection of AMPers and teachers is non-empty?)
- Johannes
[1] https://wiki.haskell.org/Functor-Applicative-Monad_Proposal
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe

On Thu, Nov 19, 2015 at 4:57 PM, Johannes Waldmann
Now, I don't want to bring on another general discussion of AMP -
That’s a curious way to frame your e-mail if this indeed is not your intent, but alright.
instead I'd like to hear from people who use monads in teaching (e.g., to define semantic domains) about how they sell "Applicative m =>" to their students.
I have almost always taught monads as if Applicative was a superclass of Monad. The strategy with which I’ve had most success is to begin describing functors as a general notion of typed computational contexts that are polymorphic in the type of the value produced by the computation, and that may have effects in the context of the computation that go beyond merely computing a value. The word «effect» is sadly suggestive of IO, and perhaps using terms like «semantic domain» instead of «computational context» and «effect» may be more universal, but it turns out to be effective. I avoid using IO as an example of a functor until the very end of the lessons on the topic of monads in an attempt to counter that unfortunate suggestion of imperative interpretation; I also avoid mentioning «return» until the very end. After explaining Functors with examples on Identity, Maybe, Either, Reader and lists, we move on to the notion of an Applicative with the same examples, and finally the notion of a Monad with the same examples. The three classes are distinguished by their expanding APIs, and it’s helpful, if you have enough time for the lesson, to show types that are Functor but not Applicative (e.g. «(,) e»). I haven’t found a helpful example of an Applicative that is not a Monad that is practical for a lesson. After that, I present interesting terms to specify complex computation using «fmap», «<$>», «<*>», «pure» and «>>=»/«=<<», and finally, I introduce do notation as a nice way of writing chained monadic computations, usually with examples based on «Data.Map.lookup». Finally, I mention «return» exists as an alias of «pure» (even though it really is part of the class — I wish that it wasn’t and it’s hard to explain why it’s even there in the first place) and caution against using it as the imperative pun may mislead their intuition (my Haskell students are in their third year of the CS program, and they’ve done a lot of imperative programming by then). We usually cover IO in a later, separate session. A couple other times we’ve tried doing IO first and the Functor/Applicative/Monad hierarchy later, but students seemed to end up more confused with that strategy (anecdotically, of course).
(The intersection of AMPers and teachers is non-empty?)
I used to have to explain the superclass should have been there but wasn’t for historical reasons, and that led to some time being wasted, and some extra, unnecessary confusion. That’s fixed now, and that particularly difficult lesson is now a bit less confusing. I’m very happy that this was finally fixed, and not having to explain that awful old situation frees up some time so I can present more examples of monad instances and monadic computations, and explain them in greater depth.

Hi, thanks for your mail! I am circulating it to my Haskell teaching colleagues, who are facing the same challenges as Johannes. Am Donnerstag, den 19.11.2015, 21:00 -0430 schrieb Manuel Gómez:
The three classes are distinguished by their expanding APIs, and it’s helpful, if you have enough time for the lesson, to show types that are Functor but not Applicative (e.g. «(,) e»).
There is the instance Monoid a => Applicative ((,) a) Do you touch upon that, or pretend it is not there? Greetings, Joachim -- Joachim “nomeata” Breitner mail@joachim-breitner.de • http://www.joachim-breitner.de/ Jabber: nomeata@joachim-breitner.de • GPG-Key: 0xF0FBF51F Debian Developer: nomeata@debian.org

I just recently had a presentation at my local usergroup
(Lambdaheads/Vienna) where I introduced the problem of `null` values and
the functional solution of using functor, applicative and monad to solve
this.
The slides are available -
https://github.com/epsilonhalbe/Talks/tree/master/20151021-LH-Func - if you
have comments on them, I'd be glad to hear, during the meetup we had quite
a discussion about it, but in the end I think everyone agreed that those
abstractions are handy and quite natural in their origination.
the tldr of it is:
that in functional languages, one major point of doing things is function
composition and to introduce new functions (in this case operators) to
solve the problem when domains do not match properly, i.e. to put the
complicated part in the composition and not bother the programmer with it.
I think the "excuse" for `return` existing is historical which I think is
no bad thing to say when teaching, because it makes students aware that
everything is being improved over time and that they might be the ones
helping.
Cheers Martin
2015-11-20 9:22 GMT+01:00 Joachim Breitner
Hi,
thanks for your mail! I am circulating it to my Haskell teaching colleagues, who are facing the same challenges as Johannes.
Am Donnerstag, den 19.11.2015, 21:00 -0430 schrieb Manuel Gómez:
The three classes are distinguished by their expanding APIs, and it’s helpful, if you have enough time for the lesson, to show types that are Functor but not Applicative (e.g. «(,) e»).
There is the instance Monoid a => Applicative ((,) a) Do you touch upon that, or pretend it is not there?
Greetings, Joachim
-- Joachim “nomeata” Breitner mail@joachim-breitner.de • http://www.joachim-breitner.de/ Jabber: nomeata@joachim-breitner.de • GPG-Key: 0xF0FBF51F Debian Developer: nomeata@debian.org
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe

On 20 November 2015 at 02:30, Manuel Gómez
I haven’t found a helpful example of an Applicative that is not a Monad that is practical for a lesson.
There's ZipList [0], which depending on the type of audience might be doable. There's also Const [1], but that needs a Monoid constraint, and since you said you considered ((,) e) as not having an Applicative, which it does have with a Monoid constraint, perhaps Const isn't suitable to you for that reason. There are more interesting examples here [2]. Erik [0] https://hackage.haskell.org/package/base-4.8.1.0/docs/Control-Applicative.ht... [1] http://hackage.haskell.org/package/base-4.8.1.0/docs/Control-Applicative.htm... [2] http://stackoverflow.com/questions/7220436/good-examples-of-not-a-functor-fu...

On 20 Nov 2015, at 11:31, Erik Hesselink
wrote: On 20 November 2015 at 02:30, Manuel Gómez
wrote: I haven’t found a helpful example of an Applicative that is not a Monad that is practical for a lesson.
There's ZipList [0], which depending on the type of audience might be doable. There's also Const [1], but that needs a Monoid constraint, and since you said you considered ((,) e) as not having an Applicative, which it does have with a Monoid constraint, perhaps Const isn't suitable to you for that reason. There are more interesting examples here [2].
Erik
[0] https://hackage.haskell.org/package/base-4.8.1.0/docs/Control-Applicative.ht... [1] http://hackage.haskell.org/package/base-4.8.1.0/docs/Control-Applicative.htm... [2] http://stackoverflow.com/questions/7220436/good-examples-of-not-a-functor-fu... _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
There are also (which I find actually useful): - `Concurrently = Concurrently (IO a)` which is Monad only IO effects are commutative. [3] - one can argue that Applicative and Monad instances aren’t compatible - `Errors` [4], which could be specialised to `Either (NonEmpty err) a` and `ap` would gather all errors! - and of course `Lift` using which `Errors` is defined. [3] https://hackage.haskell.org/package/async-2.0.2/docs/Control-Concurrent-Asyn... https://hackage.haskell.org/package/async-2.0.2/docs/Control-Concurrent-Asyn... [4] https://hackage.haskell.org/package/transformers-0.4.3.0/docs/Control-Applic... https://hackage.haskell.org/package/transformers-0.4.3.0/docs/Control-Applic... - Oleg

Hi, Am Freitag, den 20.11.2015, 12:02 +0200 schrieb Oleg Grenrus:
- `Errors` [4], which could be specialised to `Either (NonEmpty err) a` and `ap` would gather all errors!
this is actually a pretty nice and convincing example: „A effectful computation (e.g. a stateless parser) that may fail in various spots with errors, where the type system can guarantee that _all_ errors will be reported (and not just the first found).“ Obviously a Monad cannot provide this guarantee, and obviously, there are applications where this is impossible, so this nicely shows the usefulness of Applicative as a separate abstraction. Greetings, Joachim -- Joachim “nomeata” Breitner mail@joachim-breitner.de • http://www.joachim-breitner.de/ Jabber: nomeata@joachim-breitner.de • GPG-Key: 0xF0FBF51F Debian Developer: nomeata@debian.org

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA256 On 20/11/15 20:15, Joachim Breitner wrote:
Hi,
Am Freitag, den 20.11.2015, 12:02 +0200 schrieb Oleg Grenrus:
- `Errors` [4], which could be specialised to `Either (NonEmpty err) a` and `ap` would gather all errors!
this is actually a pretty nice and convincing example: „A effectful computation (e.g. a stateless parser) that may fail in various spots with errors, where the type system can guarantee that _all_ errors will be reported (and not just the first found).“
It's a pretty nice example of further splitting of the type-class hierarchy, since if given, instance Monoid a => Applicative (Either a) where -- we gather all the errors then we could not have Either (NonEmpty err), since (NonEmpty err) does not have a Monoid, only a binary, associative operation (Semigroup) . -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQEcBAEBCAAGBQJWTw/vAAoJEFkczQCvdvv0T4cH/28/pj2xqaRDHAGtoLF5mnLA phbQ9J3mbbdmTQLlx5Rp77VCBV2BvjLe4gu+sCz+Qb/cvXo9lsCpJUCZFMP6CMSF HMLD6hxZqCTyKu0/47Lmrh6AvkWFQ/YG2N99ZK4el3omoRXsBbGTxwOUBAPm5jZZ 94X6Q5jFoHOqCmeL1I7GTyx4IhnzOeMb2vTJvaiDbNUelu34ZzyzPLpaLA5uxnoC G3MZNUeHX3USPzhg2KOwno6NNmHO8E8p90TiUWriLCjr8x6VqYj+5tNx6IVamA61 0nIE2BQo/D6n8Zr+LxWmVKoaC1QK/K5wGONmIcZRDCl6IW1aGD4XkuHcWGhnQqg= =A8/9 -----END PGP SIGNATURE-----

Hi, Am Freitag, den 20.11.2015, 22:20 +1000 schrieb Tony Morris:
It's a pretty nice example of further splitting of the type-class hierarchy, since if given,
instance Monoid a => Applicative (Either a) where -- we gather all the errors
then we could not have Either (NonEmpty err), since (NonEmpty err) does not have a Monoid, only a binary, associative operation (Semigroup)
I believe that there are plans to move Semigroup into Base. Eventually, there will be a transition to Monoid having Semigroup as a superclass¹, and I guess then the instance can be changed to instance Monoid a => Applicative (Either a) where and that worry is gone. Greetings, Joachim ¹ https://ghc.haskell.org/trac/ghc/ticket/10365 and https://ghc.haskell.org/trac/ghc/wiki/Proposal/SemigroupMonoid -- Joachim “nomeata” Breitner mail@joachim-breitner.de • http://www.joachim-breitner.de/ Jabber: nomeata@joachim-breitner.de • GPG-Key: 0xF0FBF51F Debian Developer: nomeata@debian.org

On Fri, Nov 20, 2015 at 4:31 AM, Erik Hesselink
On 20 November 2015 at 02:30, Manuel Gómez
wrote: I haven’t found a helpful example of an Applicative that is not a Monad that is practical for a lesson.
There's ZipList [0], which depending on the type of audience might be doable. There's also Const [1], but that needs a Monoid constraint, and since you said you considered ((,) e) as not having an Applicative, which it does have with a Monoid constraint, perhaps Const isn't suitable to you for that reason. There are more interesting examples here [2].
An easy way to find applicative functors that are not monads is through
composition. Composing two applicative functors gives a kind of two-stage
computation, where the outer functor can affect the inner one, but can’t
depend on anything in the inner functor.
So, Compose (State s) Maybe a = s -> (Maybe a, s) will use state to create
a partial value, but whether the final value is Nothing cannot affect the
stateful part of the computation. So definitelyFail <*> modifyState will
modify the state, even though an earlier part of the computation failed.
In contrast, MaybeT (State s) a = s -> (Maybe a, s) allows communication
between the stages, so returning Nothing will abort the rest of the
computation. I.e, definitelyFail <*> modifyState will not modify the state.
If that’s too confusing for students, an example like IO (Parser a) may be
better. This cleanly separates the creation of the parser from its
execution, but giving it a monad instance would require giving the IO stage
access to the parser’s input and output.
--
Dave Menendez

On 19/11/2015, Manuel Gómez
I haven’t found a helpful example of an Applicative that is not a Monad that is practical for a lesson.
I like this one: https://hackage.haskell.org/package/regex-applicative

I'm partial to hackage.haskell.org/package/validation myself :)
On Fri, Nov 20, 2015 at 9:51 AM, M Farkas-Dyck
On 19/11/2015, Manuel Gómez
wrote: I haven’t found a helpful example of an Applicative that is not a Monad that is practical for a lesson.
I like this one: https://hackage.haskell.org/package/regex-applicative _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
-- Chris Allen Currently working on http://haskellbook.com

On 2015-11-19 04:27 PM, Johannes Waldmann wrote:
Now, I don't want to bring on another general discussion of AMP - instead I'd like to hear from people who use monads in teaching (e.g., to define semantic domains) about how they sell "Applicative m =>" to their students. (The intersection of AMPers and teachers is non-empty?)
(I do not teach Haskell. But I teach other things, and I explain Haskell things in local Haskell meetups.) I'm pretty sure we can all agree to start with Functor. This gives us fmap so we can apply a 1-ary function to 1 action. But we are greedy, we also want to apply a 2-ary function to 2 actions. Functor alone can't do this. We need at least liftA2. And then we wonder about 3-ary, 4-ary... It turns out that pure and (<*>) cover them all. To apply a 5-ary function to 5 actions, we can write the very regular pure f <*> as <*> bs <*> cs <*> ds <*> es (Given lambda calculus and Functor, the following suites have equivalent ability, so each suite could define Applicative: {pure, liftA2}, {pure, liftA2 (,)}, {pure, (<*>)}.) It also turns out that you can already write sequenceA (you didn't use all of Monad to get sequence) and traverse (you didn't use all of Monad to get mapM). So this is how I would motivate Applicative given Functor. I received the gift of 1-ary application, but then I get greedy and want n-ary application and the silver axe and the golden axe... The final transition, from Applicative to Monad, is driven by a whole new level of greed. I received the gift of n-ary application and a silver axe and a golden axe; now I want a smart axe. Here is what I mean: In the compound action fs <*> xs the sub-action fs cannot behave dependently on what "return value" the sub-action xs "returns". (Likewise for the other way round.) That data dependency is provided by Monad's (>>=) or (=<<). One operand can now peak at the "return value" of the other sub-action, and do some Turing-smart processing, before it decides what action to take. This is my version of what other people call successively expanding API.
participants (12)
-
Albert Y. C. Lai
-
Christopher Allen
-
David Menendez
-
Erik Hesselink
-
Joachim Breitner
-
Johannes Waldmann
-
M Farkas-Dyck
-
Manuel Gómez
-
Martin Heuschober
-
Oleg Grenrus
-
Tony Morris
-
Tony Morris