
I do a lot of work with parsers, and want to do more using Applicatives. That said, I'm finding it a little tedious being forced to use pointless style for a task that's well-suited to having a few names around. The idea of an applicative do notation's been kicked around on #haskell a few times (I can't find any trace of it on the mailing list, but I confess to not having searched too hard), so I thought I'd propose it here. The basic idea is to turn this: do a <- f g b <- h pure $ foo a b into this: (\a b -> pure $ foo a b) <*> (f <*> g *> h) Aside from changing >>= and >> into <*> and *>, the most significant difference from monadic do is that all the generated lambda abstractions go in front of the final "return" statement which is then fmapped across the rest of the code. Bindings are thus only in scope in the "return" statement. I believe sugared let statements can be handled similarly so long as they respect the binding discipline. This leads us to the bikeshed topic: what's the concrete syntax? The obvious way is to replace do with a new keyword - for example, ado for "applicative do". There's a nice alternative though: we can check whether a do statement meets the binding rules for an applicative block and treat it as one if so, or a monadic one if not. While not all Monads are Applicatives, code can readily be changed back using the WrappedMonad newtype - whereas existing code needn't turn on the appropriate extension in the first place. Thoughts, comments? -- flippa@flippac.org

On Fri, 2009-10-09 at 18:06 +0100, Philippa Cowderoy wrote:
This leads us to the bikeshed topic: what's the concrete syntax?
I implemented a simple Camlp4 syntax extension for Ocaml to do this. I chose the syntax: applicatively let x = foo let y = bar in <pure stuff> I quite like the word "applicatively". Your overloading suggestion sounds to me like it would require the desugaring process to know something about types, but I'm not sure. Bob -- The University of Edinburgh is a charitable body, registered in Scotland, with registration number SC005336.

Robert Atkey wrote:
On Fri, 2009-10-09 at 18:06 +0100, Philippa Cowderoy wrote:
This leads us to the bikeshed topic: what's the concrete syntax?
I implemented a simple Camlp4 syntax extension for Ocaml to do this. I chose the syntax:
applicatively let x = foo let y = bar in <pure stuff>
I quite like the word "applicatively".
In an ML context I rather like it! It doesn't really feel haskelly to me though, partly because code that looks like ANF in Haskell is normally in a do block and failing that a single let block instead of a series of nested lets.
Your overloading suggestion sounds to me like it would require the desugaring process to know something about types, but I'm not sure.
It doesn't the way I've suggested it, whereas doing it perfectly would do because not all Monads are directly Applicatives. I just reckon the imperfection isn't too big a burden applied to new code when you can newtype Monads into Applicatives on demand and get sensible code. -- flippa@flippac.org

The only issue I would have with such a notation is not being able to visually tell the difference between a monadic function (say, without a explicit type sig, which is how I write parsers), and an applicative one. I'd prefer something like foo = app blah blah If only for some visual distinction, I think it also resolves the "do knowing about types" issue. Plus, this is a good case for some kind of custom-do syntax facility. So we could make do syntax for everything. :) /Joe On Oct 9, 2009, at 1:11 PM, Robert Atkey wrote:
On Fri, 2009-10-09 at 18:06 +0100, Philippa Cowderoy wrote:
This leads us to the bikeshed topic: what's the concrete syntax?
I implemented a simple Camlp4 syntax extension for Ocaml to do this. I chose the syntax:
applicatively let x = foo let y = bar in <pure stuff>
I quite like the word "applicatively".
Your overloading suggestion sounds to me like it would require the desugaring process to know something about types, but I'm not sure.
Bob
-- The University of Edinburgh is a charitable body, registered in Scotland, with registration number SC005336.
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

I'd prefer "idiom brackets" over something do-ish for Applicatives.
Conor McBride's SHE already supports them, if you're willing to use a
custom preprocessor.
On Fri, Oct 9, 2009 at 1:45 PM, Joe Fredette
The only issue I would have with such a notation is not being able to visually tell the difference between a monadic function (say, without a explicit type sig, which is how I write parsers), and an applicative one.
I'd prefer something like
foo = app blah blah
If only for some visual distinction, I think it also resolves the "do knowing about types" issue.
Plus, this is a good case for some kind of custom-do syntax facility. So we could make do syntax for everything. :)
/Joe
On Oct 9, 2009, at 1:11 PM, Robert Atkey wrote:
On Fri, 2009-10-09 at 18:06 +0100, Philippa Cowderoy wrote:
This leads us to the bikeshed topic: what's the concrete syntax?
I implemented a simple Camlp4 syntax extension for Ocaml to do this. I chose the syntax:
applicatively let x = foo let y = bar in <pure stuff>
I quite like the word "applicatively".
Your overloading suggestion sounds to me like it would require the desugaring process to know something about types, but I'm not sure.
Bob
-- The University of Edinburgh is a charitable body, registered in Scotland, with registration number SC005336.
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

I have idiom brackets in that toy library already, but the ado syntax is
fairly useful if you want to refer to several intermediate results by name.
To work with idiom brackets you need to manually write a big lambda yourself
and them apply it. If you have a lambda that takes several arguments --
which isn't all that uncommon in a parser! -- the names you are binding and
their position in the input can get rather far apart, even using idiom
sugar. Philippa's ado sugar lets you amortize that big binding statement
over several lines and keeps the names closer to the binding.
Not sure that it warrants a syntax extension in the Haskell case, but it is
pretty convenient. =)
-Edward Kmett
On Fri, Oct 9, 2009 at 1:52 PM, Daniel Peebles
I'd prefer "idiom brackets" over something do-ish for Applicatives. Conor McBride's SHE already supports them, if you're willing to use a custom preprocessor.
On Fri, Oct 9, 2009 at 1:45 PM, Joe Fredette
wrote: The only issue I would have with such a notation is not being able to visually tell the difference between a monadic function (say, without a explicit type sig, which is how I write parsers), and an applicative one.
I'd prefer something like
foo = app blah blah
If only for some visual distinction, I think it also resolves the "do knowing about types" issue.
Plus, this is a good case for some kind of custom-do syntax facility. So we could make do syntax for everything. :)
/Joe
On Oct 9, 2009, at 1:11 PM, Robert Atkey wrote:
On Fri, 2009-10-09 at 18:06 +0100, Philippa Cowderoy wrote:
This leads us to the bikeshed topic: what's the concrete syntax?
I implemented a simple Camlp4 syntax extension for Ocaml to do this. I chose the syntax:
applicatively let x = foo let y = bar in <pure stuff>
I quite like the word "applicatively".
Your overloading suggestion sounds to me like it would require the desugaring process to know something about types, but I'm not sure.
Bob
-- The University of Edinburgh is a charitable body, registered in Scotland, with registration number SC005336.
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

Excerpts from Edward Kmett's message of Fri Oct 09 20:04:08 +0200 2009:
I have idiom brackets in that toy library already, but the ado syntax is fairly useful if you want to refer to several intermediate results by name. To work with idiom brackets you need to manually write a big lambda yourself and them apply it. If you have a lambda that takes several arguments -- which isn't all that uncommon in a parser! -- the names you are binding and their position in the input can get rather far apart, even using idiom sugar. Philippa's ado sugar lets you amortize that big binding statement over several lines and keeps the names closer to the binding.
You can still name intermediate *computations* using local bindings, right? Then you just have to use the named computations in idioms brackets. -- Nicolas Pouillard http://nicolaspouillard.fr

Nicolas Pouillard wrote:
Excerpts from Edward Kmett's message of Fri Oct 09 20:04:08 +0200 2009:
I have idiom brackets in that toy library already, but the ado syntax is fairly useful if you want to refer to several intermediate results by name. To work with idiom brackets you need to manually write a big lambda yourself and them apply it. If you have a lambda that takes several arguments -- which isn't all that uncommon in a parser! -- the names you are binding and their position in the input can get rather far apart, even using idiom sugar. Philippa's ado sugar lets you amortize that big binding statement over several lines and keeps the names closer to the binding.
You can still name intermediate *computations* using local bindings, right? Then you just have to use the named computations in idioms brackets.
Not really good enough, because of all the computations whose results aren't used. Being able to tell at a glance which bits of the parser are handling data for the abstract syntax and which're structure to guide the parser is pretty handy. -- flippa@flippac.org

Good trick. I just added 'ado' to my little scheme monad library. ;)
-Edward Kmett
On Fri, Oct 9, 2009 at 1:06 PM, Philippa Cowderoy
I do a lot of work with parsers, and want to do more using Applicatives. That said, I'm finding it a little tedious being forced to use pointless style for a task that's well-suited to having a few names around. The idea of an applicative do notation's been kicked around on #haskell a few times (I can't find any trace of it on the mailing list, but I confess to not having searched too hard), so I thought I'd propose it here.
The basic idea is to turn this:
do a <- f g b <- h pure $ foo a b
into this:
(\a b -> pure $ foo a b) <*> (f <*> g *> h)
Aside from changing >>= and >> into <*> and *>, the most significant difference from monadic do is that all the generated lambda abstractions go in front of the final "return" statement which is then fmapped across the rest of the code. Bindings are thus only in scope in the "return" statement. I believe sugared let statements can be handled similarly so long as they respect the binding discipline.
This leads us to the bikeshed topic: what's the concrete syntax? The obvious way is to replace do with a new keyword - for example, ado for "applicative do". There's a nice alternative though: we can check whether a do statement meets the binding rules for an applicative block and treat it as one if so, or a monadic one if not. While not all Monads are Applicatives, code can readily be changed back using the WrappedMonad newtype - whereas existing code needn't turn on the appropriate extension in the first place.
Thoughts, comments?
-- flippa@flippac.org _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
participants (6)
-
Daniel Peebles
-
Edward Kmett
-
Joe Fredette
-
Nicolas Pouillard
-
Philippa Cowderoy
-
Robert Atkey