extending Do notation

grep -r ">>=" base | head -3 getExecutablePath = _NSGetExecutablePath >>= realpath
grep -r "flip" base | head -3 ... (o,n,[] ) -> return (foldl (flip id) defaultOptions o, n)
grep -r ">>=" base | head -3 getExecutablePath = _do realpath { _NSGetExecutablePath }
grep -r "flip" base | head -3 ... (o,n,[] ) -> return (foldl (flip id) defaultOptions o, n) -- leave
#The problem then peek p_argv >>= peek >>= peekFilePath ... = getFileSystemEncoding >>= \enc -> GHC.withCString enc fp f peekCString s = getForeignEncoding >>= flip GHC.peekCString s peekCStringLen s = getForeignEncoding >>= flip GHC.peekCStringLen s I don't know how often i've seen this one ... >>= flip ... when really we it should have been ... {...} Only because we can't just execute an IO action and fill in the result. And this list doesn't even include examples where the programmer had to resort to making a pointless temp variable just to avoid using too many complicated functions. #The solution then peekFilePath { peek {peek p_argv} } ... = do GHC.withCString {getFileSystemEncoding} fp f peekCString s = GHC.peekCString {getForeignEncoding} s peekCStringLen s = GHC.peekCStringLen {getForeignEncoding} s I think there is no use of {} in haskell that does not come after a key word but has an expression inside. But it could be some other syntax too. silvio

On Tue, May 20, 2014 at 7:58 PM, silvio
I don't know how often i've seen this one ... >>= flip ... when really we it should have been ... {...}
Your email is on the assertion-heavy side. Would you reconsider restating your case? Just to take a small slice, instead of
getExecutablePath = _NSGetExecutablePath >>= realpath
you'd prefer to use braces like this:
getExecutablePath = _do realpath { _NSGetExecutablePath }
You could already write in today's haskell:
getExecutablePath = realpath =<< _NSGetExecutablePath
-- Kim-Ee

Your email is on the assertion-heavy side. Would you reconsider restating your case?
1) >>= flip is ugly 2) you can't use >>= in an if condition 3) or imagine you want to fill it in some 3-tuple or a record type. 4) res <- fmap pureFunction ioFunction === let res = pureFunction { ioFunction} There are tons of cases that we have solved with complicated combinations of operators and functions that could be displayed much clearer with this notation. silvio

On Tue, 20 May 2014 15:39:45 +0200, silvio
Your email is on the assertion-heavy side. Would you reconsider restating your case?
1) >>= flip is ugly
2) you can't use >>= in an if condition
3) or imagine you want to fill it in some 3-tuple or a record type.
4) res <- fmap pureFunction ioFunction === let res = pureFunction { ioFunction}
There are tons of cases that we have solved with complicated combinations of operators and functions that could be displayed much clearer with this notation.
Are we reinventing idiom brackets here?

On Tue, May 20, 2014 at 8:39 PM, silvio
1) >>= flip is ugly
Indeed. Many things are ugly in haskell. Improvements exact their own costs too.
2) you can't use >>= in an if condition
Could you give an example of the if condition you want an >>= in?
3) or imagine you want to fill it in some 3-tuple or a record type.
What does this mean?
4) res <- fmap pureFunction ioFunction === let res = pureFunction { ioFunction}
From a distance, let and monadic bind are just different forms of name binding.
But haskell's let has an effectlessness that makes it declaratively different from its cousin in, say, ocaml. This is no small change you're proposing. -- Kim-Ee

2) you can't use >>= in an if condition
look at the first if in base package that i is not a comment ok <- getProcessTimes ... if toBool ok then do since getProcess has many actument's this is good code, but imagine it was a short IO function if toBool { getProcessTimes ... } then do looks much better you can't pipe the result of getProcessTimes into the if conditional. Unless you use a lambda of course.
3) or imagine you want to fill it in some 3-tuple or a record type.
What does this mean?
someIOFunction ({getProcessTimes ...}, foo, bar) someIOFunction (foo { bar = {getProcessTimes ...}})
4) res <- fmap pureFunction ioFunction === let res = pureFunction { ioFunction}
From a distance, let and monadic bind are just different forms of name binding.
But haskell's let has an effectlessness that makes it declaratively different from its cousin in, say, ocaml.
This is no small change you're proposing.
You might have misunderstood. The 'let' in the do notation is already different from the normal 'let' in that it doesn't have an 'in' for example. {} should of course only work inside a do block. silvio

On Tue, May 20, 2014 at 9:27 PM, silvio
4) res <- fmap pureFunction ioFunction === let res = pureFunction { ioFunction}
From a distance, let and monadic bind are just different forms of name binding.
But haskell's let has an effectlessness that makes it declaratively different from its cousin in, say, ocaml.
This is no small change you're proposing.
You might have misunderstood. The 'let' in the do notation is already different from the normal 'let' in that it doesn't have an 'in' for example. {} should of course only work inside a do block.
But you know about the desugaring for let statements within do blocks, yes? There's nothing magical about let. Which is to say, there's a regularity about let that current haskell allows us to take for granted. What you're proposing makes the let in a do-block different from a let 'in' a do-block, braces notwithstanding i.e. do let ... { ... } vs do let ... in So to return to this:
4) res <- fmap pureFunction ioFunction === let res = pureFunction { ioFunction}
If res in "let res = ..." is not referred to anywhere in the do-block created by desugaring, it's as if the let didn't exist. On the other hand, for "res <- ... ioFunction", the effect of ioFunction is realized regardless of whether res is referenced. -- Kim-Ee

Hi stmtpart1 { exp } stmtpart2 should desugar to x <- exp stmtpart1 x stmtpart2 it's not very complicated and i don't see why it shouldn't be done in the let case but i don't care. monadic bind would be enough for me. silvio

On Tue, May 20, 2014 at 11:57 PM, silvio
stmtpart1 { exp } stmtpart2
should desugar to
x <- exp stmtpart1 x stmtpart2
Ok, your proposal looks a lot clearer now. And in fact I've been mulling over the same problem. Let's kick it up a notch: Suppose what we really want to write is just: stmtpart1 exp stmtpart2 so that we do away with brackets, braces, and all other carpal-tunnelling punctuation-that-looks-like-line-noise? How would that work? -- Kim-Ee

Hi, silvio wrote:
4) res <- fmap pureFunction ioFunction === let res = pureFunction { ioFunction}
I think this translation is wrong. The left-hand side executes the side-effects of the ioFunction exactly once. The right-hand side looks like it would execute the side-effects of ioFunction everytime res is used. Maybe you want something more like this: res <- pureFunction { ioFunction } which would desugar to something like this: res <- do temp <- ioFunction return (pureFunction temp) Can you write desugaring rules that explain how your { ... } notation would work? Tillmann

I think this translation is wrong. The left-hand side executes the side-effects of the ioFunction exactly once. The right-hand side looks like it would execute the side-effects of ioFunction everytime res is used.
I knew I should have left the let thing alone. It looks a bit strange to me too. But think if it this way, it's the {} that does the IO not the let. I'm not en expert in formality but it should work something like this stmtpart1 { exp } stmtpart2 should desugar to x <- exp stmtpart1 x stmtpart2 but as I said I don't insist on this working in the let case. It's not the main point.

Hi Silvio,
On 20 May 2014 18:10, silvio
stmtpart1 { exp } stmtpart2
should desugar to
x <- exp stmtpart1 x stmtpart2
As Niklas already pointed, and his message seems to have been ignored for some reason, search for "Idiom brackets" -- they solve a very similar (same?) problem. Ozgur.

As Niklas already pointed, and his message seems to have been ignored for some reason, search for "Idiom brackets" -- they solve a very similar (same?) problem.
Yes I know I looked it up and it was very complicated. I didn't understand everything. But as it looks like you would have to put everything into that bracket. The idea here is that you just put the (IO a) in the bracket. silvio

Hi, silvio wrote:
I'm not en expert in formality but it should work something like this
stmtpart1 { exp } stmtpart2
should desugar to
x <- exp stmtpart1 x stmtpart2
but as I said I don't insist on this working in the let case.
Oh, I think this would work fine with let, if you do it as follows: let x = stmtpart1 { exp } stmtpart2 more stuff x other things desugars to let x = do temp <- exp stmtpart1 temp stmtpart2 more stuff x other things This is just your desugaring from above, but inside the body of the let. But what about lambdas: stmtpart1 (\x -> {exp}) stmtpart2 And what about nested braces: stmtpart1 { something { more } whatever } stmtpart2 There are lots of other cases to consider :) silvio wrote about idiom brackets:
Yes I know I looked it up and it was very complicated. I didn't understand everything.
Is your proposal more or less complicated? It seems less complicated at first, but if you fill in all the details and work out all the different cases, maybe it ends up being more complicated. Tillmann

let x = stmtpart1 { exp } stmtpart2 more stuff x other things
that doesn't make sense stmts can only occure in a do not in a let stmt -> exp ; | pat <- exp ; | let decls ; | ;
But what about lambdas:
stmtpart1 (\x -> {exp}) stmtpart2
And what about nested braces:
stmtpart1 { something { more } whatever } stmtpart2
There are lots of other cases to consider :)
Ok now we have finally come to implementation. I don't know a lot of compiler internals but it could work something along those lines. make "{ exp }" an expression. if you are parsing a statement there needs to be some context so an an expression can make use of the fact that it's in a do block. the expression "{ exp }" tells the statement to do "newvarname <- exp" and returns newvarname. Of course the order in which these "newvarname <- exp" will get executed is the order in which the expression results are returned, in other of the closing brackets. This should cover the lambda question and the nested question. silvio

Hi, silvio wrote:
[...] This should cover the lambda question and the nested question.
No, I don't understand how this covers the lambda case. For example, how is the following desugared: do print (map (\name -> {readFile name}) ["foo", "bar"]) It would be convenient if this would mean something like: do contents <- mapM (\name -> readFile name) ["foo", "bar"] print contents But I don't understand how the implementation you propose can figure this out. Tillmann

On 05/20/2014 08:44 PM, Tillmann Rendel wrote:
Hi,
silvio wrote:
[...] This should cover the lambda question and the nested question.
No, I don't understand how this covers the lambda case. For example, how is the following desugared:
do print (map (\name -> {readFile name}) ["foo", "bar"])
It would be convenient if this would mean something like:
do contents <- mapM (\name -> readFile name) ["foo", "bar"] print contents
I see sorry I didn't consider that there would be new variables. syntax changed from {exp} to (<-exp) An other thing to consider is functions. This seems really awesome syntax. Unfortunately, this might cause some troubles because functions can be monads. do print map (<-readFile) ["foo","bar"] silvio

A simple solution would be to say that (<- exp) can only contain variables bound by do and leave the lambda out for now. This should make the execution order more or less clear and should cover most cases. If the need arose, it could still be extended to incorporate more things later. silvio

On Tue, May 20, 2014 at 1:02 PM, Kim-Ee Yeoh
On Wed, May 21, 2014 at 2:47 AM, silvio
wrote: do print map (<-readFile) ["foo","bar"]
The closest current Haskell can come to this is
print =<< mapM readFile ["foo","bar"]
And I agree that the manual effect typing, the requisite =<< and the mapM for map, can be a pain.
For an example that's harder to convert, I occasionally have something like this: f x | a && (b > 1 || (c && d)) && e = ... Now if 'c' becomes monadic you have to rewrite the whole expression in an entirely different (and much noisier) style. Not just all the lifting, but you can't use infix operators anymore. It really does feel like there are two languages (or dialects), with different idioms and syntax. You can translate between them without much complicated effort, but it's still a manual translation.

f x | a && (b > 1 || (c && d)) && e = ...
Now if 'c' becomes monadic you have to rewrite the whole expression in an entirely different (and much noisier) style. Not just all the lifting, but you can't use infix operators anymore. It really does feel like there are two languages (or dialects), with different idioms and syntax. You can translate between them without much complicated effort, but it's still a manual translation.
Good example, but i don't think you can have monads in a guard. Also I'd go for the temporary variable instead of lifting.

On 14-05-20 08:58 AM, silvio wrote:
Only because we can't just execute an IO action and fill in the result. And this list doesn't even include examples where the programmer had to resort to making a pointless temp variable just to avoid using too many complicated functions.
I agree that requiring extra variable names to express data propagation is a problem. I disagree that any notation that goes like third_effect {first_effect} {second_effect} is a solution. I have written it to highlight the problem: the order of the effects is neither entirely left-to-right nor entirely right-to-left, but rather a haphazard "start somewhere in the middle, go right for a while, now suddenly jump back to the left". This is also my second biggest gripe with Lisp, Scheme, SML, Caml, every impure functional language. One thing the do-notation gets right is that I/O effect order is the simple top-to-bottom. The solution is to liberate programming from the plain text file. Draw a dataflow-like diagram. Arrange effect boxes in one order to indicate effect order. Draw lines or curves between them to indicate data propagation and/or parameter passing. Can programming be liberated from the plain text file?

On 2014-05-20 20:59, Albert Y. C. Lai wrote:
Can programming be liberated from the plain text file?
No. I hate to be downer, but every single time I've seen a proposal for this it has failed to account for how, *exactly*, it is actually different in any meaningful way from the failed attempts at addressing this issue. I've often been quite tempted to draw up a checklist à la the infamous spam-fighting checklist for why $YOUR_IDEA_FOR_NON-TEXT-BASED_PROGRAMMING won't work -- at the very least it'd serve as a time-saver whenever this comes up :). We can all dream, but unless and until someone comes up with something *radically* different from previous attempts, it just ain't going to happen. Regards,

There are plenty of counterexamples. Variations on visual function blocks
abound in engineering circles.
A better question might be whether the HMI bandwidth can be increased
beyond what's possible with a keyboard.
Cheers,
Darren
On May 20, 2014 12:26 PM, "Bardur Arantsson"
On 2014-05-20 20:59, Albert Y. C. Lai wrote:
Can programming be liberated from the plain text file?
No.
I hate to be downer, but every single time I've seen a proposal for this it has failed to account for how, *exactly*, it is actually different in any meaningful way from the failed attempts at addressing this issue. I've often been quite tempted to draw up a checklist à la the infamous spam-fighting checklist for why $YOUR_IDEA_FOR_NON-TEXT-BASED_PROGRAMMING won't work -- at the very least it'd serve as a time-saver whenever this comes up :).
We can all dream, but unless and until someone comes up with something *radically* different from previous attempts, it just ain't going to happen.
Regards,
_______________________________________________ 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

On Wed, May 21, 2014 at 5:12 AM, Darren Grant
There are plenty of counterexamples. Variations on visual function blocks abound in engineering circles.
Let's not forget The World's Most Popular Functional Language: Spreadsheets [1]. They don't call themselves programmers but that doesn't mean the work they do all day long hacking cells and formulas and the occasional launch-the-missiles excel macro isn't programming. [1] http://research.microsoft.com/en-us/um/people/simonpj/Papers/excel/ -- Kim-Ee

On Tue, May 20, 2014 at 8:33 PM, Kim-Ee Yeoh
Let's not forget The World's Most Popular Functional Language: Spreadsheets [1].
I dunno, I think makefiles might give them a run for the money when it comes to declarative functional languages out there. and they are monadic too! John -- John Meacham - http://notanumber.net/

On Thu, May 22, 2014 at 4:37 AM, John Meacham
I dunno, I think makefiles might give them a run for the money when it comes to declarative functional languages out there. and they are monadic too!
Yes. Makefile programming is declarative programming indeed. Makefiles are textfiles though. So to return to the theme of "Can programming be liberated from textfiles?", I posited spreadsheets as a form of programming with no textfiles in sight. -- Kim-Ee

On 22 May 2014 14:48, Kim-Ee Yeoh
On Thu, May 22, 2014 at 4:37 AM, John Meacham
wrote: I dunno, I think makefiles might give them a run for the money when it comes to declarative functional languages out there. and they are monadic too!
Yes. Makefile programming is declarative programming indeed. Makefiles are textfiles though.
So to return to the theme of "Can programming be liberated from textfiles?", I posited spreadsheets as a form of programming with no textfiles in sight.
CSVs? -- Ivan Lazar Miljenovic Ivan.Miljenovic@gmail.com http://IvanMiljenovic.wordpress.com

On Wed, May 21, 2014 at 9:48 PM, Kim-Ee Yeoh
So to return to the theme of "Can programming be liberated from textfiles?", I posited spreadsheets as a form of programming with no textfiles in sight.
'go' is a little in this direction in that there is a standard syntax aware formatter that is part of the language. So although there are text files, they have been normalized and spit through an AST. John -- John Meacham - http://notanumber.net/

The solution is to liberate programming from the plain text file.
Sounds a lot like "liberating literature from text". Sure, there are some kinds of media that are very non-textual... but they aren't literature anymore. And no, whatever Lispers want to believe in, program is not AST. Program is TEXT. Even if it's a Lisp program.

On Tue, May 20, 2014 at 2:51 PM, MigMit
And no, whatever Lispers want to believe in, program is not AST. Program is TEXT.
No, a program is a bunch of bits the computer can execute. It can be represented as TEXT, or an AST, or even a diagram in some graphical programming tool somewhere - all of which we also confusingly call a "program". As noted by others, attempts to get away from TEXT have been going on for decades. So far every attempt has failed - for reasons also noted by others.

On 21 May 2014, at 00:32, Mike Meyer
On Tue, May 20, 2014 at 2:51 PM, MigMit
wrote: And no, whatever Lispers want to believe in, program is not AST. Program is TEXT. No, a program is a bunch of bits the computer can execute. It can be represented as TEXT, or an AST, or even a diagram in some graphical programming tool somewhere - all of which we also confusingly call a "program".
Incorrect. There are programs in pseudocode, programs for MIX, programs for machines they don't make anymore. Ada Lovelace created some programs for Babbidge's machine. Program can be buggy, or unfinished. Neither of these types of programs can be executed, but they are still programs. I'd say that what makes program a program is not how it's executed, it's how it is read. By humans. And, as for now, there are no adequate alternatives to text representation. They all lose coding style, at least.

On Tue, May 20, 2014 at 3:44 PM, MigMit
On 21 May 2014, at 00:32, Mike Meyer
wrote: On Tue, May 20, 2014 at 2:51 PM, MigMit
wrote: And no, whatever Lispers want to believe in, program is not AST. Program is TEXT. No, a program is a bunch of bits the computer can execute. It can be represented as TEXT, or an AST, or even a diagram in some graphical programming tool somewhere - all of which we also confusingly call a "program".
Incorrect. There are programs in pseudocode, programs for MIX, programs for machines they don't make anymore. Ada Lovelace created some programs for Babbidge's machine. Program can be buggy, or unfinished. Neither of these types of programs can be executed, but they are still programs.
Incorrect. Those are all representations of programs. Whether they can or can't be executed is immaterial to that status. As I said, it's common to call a representation of a program a program as well, because the context lets the reader sort it out. But in this context, it matters, because we're talking about alternative representations for programs. Turning your Haskell representation of a program into an actual program generally requires it to be translated through multiple different representations: core, C, assembler and finally you get a program. There may be some ASTs in there as well. Hopefully, they all preserve the intent of the programmer (otherwise, one or more of the steps in your tool chain is buggy).
I'd say that what makes program a program is not how it's executed, it's how it is read. By humans.
I'd say that's what makes a text (or whatever) a representation of a program: how it's read by humans. Whether or not it can be turned into an actual, honest to goddesses executable program is another issue entirely.
And, as for now, there are no adequate alternatives to text representation.
Now you got it! To add the proper emphasis: there are no adequate alternatives to text *representation*. Exactly right! The text is a representation of a program, not a program.

Incorrect. There are programs in pseudocode, programs for MIX, programs for machines they don't make anymore. Ada Lovelace created some programs for Babbidge's machine. Program can be buggy, or unfinished. Neither of these types of programs can be executed, but they are still programs.
Incorrect. Those are all representations of programs.
Of what programs?
Whether they can or can't be executed is immaterial to that status. As I said, it's common to call a representation of a program a program as well, because the context lets the reader sort it out. But in this context, it matters, because we're talking about alternative representations for programs.
No, it doesn't, because there are no alternative representations and, most of the time, nothing to represent. I'll elaborate on both points. Let's start with the second part. The executable, compiled from source (even if compilation IS possible) depends on overwhelming amount of variables. Compiler. It's version. Operating system. Optimization flags. Libraries' versions (not to mention that libraries, as binaries, also depend on a lot of things). Linker. Hardware platform. Etc. There is NOTHING common to all possible binaries produced by compiling the same source. Therefore, there is nothing to represent. Now, about there being no alternative representations. It's true that small changes of syntax usually don't really change the program. In the same way as changing "Philosopher's stone" to "Sorcerer's stone" in US didn't really change the first Harry Potter book. That doesn't mean syntax is irrelevant. Program conveys some meaning, and syntax plays it's part. Joining the chapters of the book together, for instance, will make it less readable. The simplest programming example probably is quicksort (x:xs) = [y | y <- xs, y < x] ++ x ++ [y | y <- xs, y >= x] This can be written in one line, and AST would be the same. But the layout here emphasizes the symmetry of algorithm, helping the author to express the meaning of what he is doing. Now, that's a very simple example, of course, but things like that are everywhere. No other represenation can capture such details, and they matter. So, there are no alternative representations. There could be some other views of the program — like graphical class hierarchies — but they aren't "representations", as the chart presented by company's top managers to shareholders is not the representation of all the company's documentation. Of course, you can actually start from some other "representation" — for example, graphical. That would be like writing a novel by drawing pictures.

On May 20, 2014 12:00 PM, "Albert Y. C. Lai"
On 14-05-20 08:58 AM, silvio wrote:
Only because we can't just execute an IO action and fill in the result. And this list doesn't even include examples where the programmer had to resort to making a pointless temp variable just to avoid using too many complicated functions.
I agree that requiring extra variable names to express data propagation
is a problem. I disagree that any notation that goes like
third_effect {first_effect} {second_effect}
is a solution. I have written it to highlight the problem: the order of
the effects is neither entirely left-to-right nor entirely right-to-left, but rather a haphazard "start somewhere in the middle, go right for a while, now suddenly jump back to the left". This is also my second biggest gripe with Lisp, Scheme, SML, Caml, every impure functional language.
One thing the do-notation gets right is that I/O effect order is the
simple top-to-bottom.
The solution is to liberate programming from the plain text file.
Draw a dataflow-like diagram. Arrange effect boxes in one order to
indicate effect order. Draw lines or curves between them to indicate data propagation and/or parameter passing.
Can programming be liberated from the plain text file?
Having done a number of projects in Max/MSP and PD, I have to say this is a horribly inefficient programming interface. It seems attractive in small doses, but it doesn't scale well. Additionally it's not at all clear how to design an editor that allows for decent automation, which can slow down many workflows. If you're interested in this interface, I'd suggest that you try PD for a while.
participants (15)
-
Albert Y. C. Lai
-
Bardur Arantsson
-
Darren Grant
-
Evan Laforge
-
Ivan Lazar Miljenovic
-
John Lato
-
John Meacham
-
Kim-Ee Yeoh
-
mantkiew@gsd.uwaterloo.ca
-
MigMit
-
Mike Meyer
-
Niklas Haas
-
Ozgur Akgun
-
silvio
-
Tillmann Rendel