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 [hidden email] http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe |
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 <[hidden email]> wrote: Because of AMP, I have to rewrite slides and example code _______________________________________________ Haskell-Cafe mailing list [hidden email] http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe |
In reply to this post by Johannes Waldmann-2
On Thu, Nov 19, 2015 at 4:57 PM, Johannes Waldmann
<[hidden email]> wrote: > 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. _______________________________________________ Haskell-Cafe mailing list [hidden email] http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe |
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 [hidden email] • http://www.joachim-breitner.de/ Jabber: [hidden email] • GPG-Key: 0xF0FBF51F Debian Developer: [hidden email] _______________________________________________ Haskell-Cafe mailing list [hidden email] http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe signature.asc (836 bytes) Download Attachment |
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 <[hidden email]>: Hi, _______________________________________________ Haskell-Cafe mailing list [hidden email] http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe |
In reply to this post by Manuel Gómez
On 20 November 2015 at 02:30, Manuel Gómez <[hidden email]> 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.html#t:ZipList [1] http://hackage.haskell.org/package/base-4.8.1.0/docs/Control-Applicative.html#v:Const [2] http://stackoverflow.com/questions/7220436/good-examples-of-not-a-functor-functor-applicative-monad _______________________________________________ Haskell-Cafe mailing list [hidden email] 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-Async.html#t:Concurrently [4] https://hackage.haskell.org/package/transformers-0.4.3.0/docs/Control-Applicative-Lift.html#t:Errors - Oleg _______________________________________________ Haskell-Cafe mailing list [hidden email] http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe signature.asc (859 bytes) Download Attachment |
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 [hidden email] • http://www.joachim-breitner.de/ Jabber: [hidden email] • GPG-Key: 0xF0FBF51F Debian Developer: [hidden email] _______________________________________________ Haskell-Cafe mailing list [hidden email] http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe signature.asc (836 bytes) Download Attachment |
-----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----- _______________________________________________ Haskell-Cafe mailing list [hidden email] http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe |
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 [hidden email] • http://www.joachim-breitner.de/ Jabber: [hidden email] • GPG-Key: 0xF0FBF51F Debian Developer: [hidden email] _______________________________________________ Haskell-Cafe mailing list [hidden email] http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe signature.asc (836 bytes) Download Attachment |
In reply to this post by Manuel Gómez
On 19/11/2015, Manuel Gómez <[hidden email]> 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 [hidden email] http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe |
I'm partial to hackage.haskell.org/package/validation myself :) On Fri, Nov 20, 2015 at 9:51 AM, M Farkas-Dyck <[hidden email]> wrote: On 19/11/2015, Manuel Gómez <[hidden email]> wrote: Chris Allen Currently working on http://haskellbook.com _______________________________________________ Haskell-Cafe mailing list [hidden email] http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe |
In reply to this post by Erik Hesselink
On Fri, Nov 20, 2015 at 4:31 AM, Erik Hesselink <[hidden email]> wrote:
On 20 November 2015 at 02:30, Manuel Gómez <[hidden email]> wrote: 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. _______________________________________________ Haskell-Cafe mailing list [hidden email] http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe |
In reply to this post by Johannes Waldmann-2
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. _______________________________________________ Haskell-Cafe mailing list [hidden email] http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe |
Free forum by Nabble | Edit this page |