From simonmar at microsoft.com Thu Jan 4 11:15:45 2007 From: simonmar at microsoft.com (Simon Marlow) Date: Thu Jan 4 11:12:11 2007 Subject: defaults In-Reply-To: <20061121093333.5923ed8d.Malcolm.Wallace@cs.york.ac.uk> Message-ID: haskell-prime-bounces@haskell.org wrote: > Simon Peyton-Jones writes: > >>> My suggestion is that there should be a single default type >>> per class. >> >> Ah, I missed that. > > I suppose, because the proposed new rule is so simple and short, it is > rather easy to miss its implications, especially if you are used to > thinking in terms of the existing more complicated rule. > >> Suppose I have >> default Eq Integer >> default Fractional Float >> and I have (Eq a, Fractional a). Does 'a' resolve to > Integer or to Float? Perhaps a few examples on the proposal > page would be useful for readers? > > The proposed rule is that defaulting applies *after* simplification of > the context. So, although you initially infer > (Eq a, Fractional a) => a > but after simplification, this becomes > (Fractional a) => a > so there is a single class to be defaulted, and Float is chosen. Is your proposal supposed to be backwards compatible with Haskell 98 for programs that don't have default declarations? If so, then I offer a counter example: toRational pi will default pi to Double in Haskell 98, but will be an error under your proposal, because the two constraints (Real and Floating) disagree on the default. dflt.hs:3:7: Warning: Defaulting the following constraint(s) to type `Double' `Real a' arising from use of `toRational' at dflt.hs:3:7-19 `Floating a' arising from use of `pi' at dflt.hs:3:18-19 In the expression: toRational pi In the definition of `test': test = toRational pi You can generate more examples using Enum/Fractional combinations, but it's dubious whether Float & Double should be instances of Enum anyway. Cheers, Simon From ijones at syntaxpolice.org Sun Jan 7 22:28:08 2007 From: ijones at syntaxpolice.org (Isaac Jones) Date: Sun Jan 7 22:24:19 2007 Subject: patch applied (haskell-prime-report): very rough draft of informal pattern-guard (qualifiers) explanations Message-ID: <20070108032808.GA12305@cvs.haskell.org> Sun Jan 7 19:26:27 PST 2007 ijones@syntaxpolice.org * very rough draft of informal pattern-guard (qualifiers) explanations This is a very rough draft in order to get some discussion going, and does not touch the semantic explanations, which will still need to be done. M ./report/exps.verb -48 +63 From ijones at galois.com Sun Jan 7 22:45:04 2007 From: ijones at galois.com (isaac jones) Date: Sun Jan 7 22:41:29 2007 Subject: very rough draft of informal pattern-guard (qualifiers) explanations In-Reply-To: <20070108032808.GA12305@cvs.haskell.org> References: <20070108032808.GA12305@cvs.haskell.org> Message-ID: <1168227905.15873.177.camel@localhost.localdomain> I just pushed a very rough draft of the plain, informal text for pattern guards. I'm also attaching the patch. http://darcs.haskell.org/haskell-prime-report/report/exps.verb I'd like some feedback about the approach I'm taking, which varies slightly from the description in the 2000 HW paper. Since "pattern guards" are defined basically as in list comprehensions, I've pulled a bit of that text into its own section. In the list comprehensions section, pattern guards are referred to as "qualifiers", so I've kept that name. (From Simon's original memo, it seems that the generators within the qualifiers are pattern guards.) So now there's a section that explains qualifiers, including the nested environment nature. In many places, I've removed references to guards and replaced them with references to qualifiers. I've also consolidated text that explains guards, which was previously found in various locations, into that single section as above. I haven't touched the more semantic bits yet; I'd like some feedback on my overall approach first. I've brashly pushed these changes into our darcs repository of the report in the hopes that others on the committee (or indeed, within the community) will begin to be a bit more brash. Alas, I'm unable to actually build the report at the moment. If anyone knows how, please add instructions to the repository, or send them to me and I'll add them. peace, isaac p.s. the pattern guard wiki page is here: http://hackage.haskell.org/trac/haskell-prime/wiki/PatternGuards p.p.s. http://www.haskell.org/pipermail/cvs-ghc/2007-January/033592.html From simonmar at microsoft.com Mon Jan 8 06:07:01 2007 From: simonmar at microsoft.com (Simon Marlow) Date: Mon Jan 8 06:03:11 2007 Subject: patch applied (haskell-prime-report): add clean target Message-ID: <20070108110701.GA18959@cvs.haskell.org> Mon Jan 8 02:59:08 PST 2007 Simon Marlow * add clean target M ./tools/Makefile +4 From simonmar at microsoft.com Mon Jan 8 06:07:02 2007 From: simonmar at microsoft.com (Simon Marlow) Date: Mon Jan 8 06:03:13 2007 Subject: patch applied (haskell-prime-report): create $(RELEASE_DIR) if necessary Message-ID: <20070108110702.GA18981@cvs.haskell.org> Mon Jan 8 03:01:50 PST 2007 Simon Marlow * create $(RELEASE_DIR) if necessary M ./report/Makefile +1 From simonmar at microsoft.com Mon Jan 8 06:12:07 2007 From: simonmar at microsoft.com (Simon Marlow) Date: Mon Jan 8 06:08:17 2007 Subject: patch applied (haskell-prime-report): some notes on how to build it. Message-ID: <20070108111207.GA19065@cvs.haskell.org> Mon Jan 8 03:11:48 PST 2007 Simon Marlow * some notes on how to build it. M ./README -6 +26 From dmhouse at gmail.com Mon Jan 8 08:42:59 2007 From: dmhouse at gmail.com (David House) Date: Mon Jan 8 08:39:09 2007 Subject: patch applied (haskell-prime-report): some notes on how to build it. In-Reply-To: <20070108111207.GA19065@cvs.haskell.org> References: <20070108111207.GA19065@cvs.haskell.org> Message-ID: On 08/01/07, Simon Marlow wrote: > Mon Jan 8 03:11:48 PST 2007 Simon Marlow > * some notes on how to build it. > > M ./README -6 +26 Using the flex version 2.5.31, straight out of apt, I get the following error: flex -t -8 verbatim.lex > verbatim.c || ( rm -f verbatim.c && exit 1 ) verbatim.lex:75: warning, rule cannot be matched cc -c verbatim.c -o verbatim.o :561:25: error: macro "yywrap" passed 1 arguments, but takes just 0 make: *** [verbatim] Error 1 Using the flex-old package, which is version 2.5.4a, it works. I guess this means our flex files are legacy. Could they be updated to work with the latest flex? -- -David House, dmhouse@gmail.com From Malcolm.Wallace at cs.york.ac.uk Mon Jan 8 10:09:48 2007 From: Malcolm.Wallace at cs.york.ac.uk (Malcolm Wallace) Date: Mon Jan 8 10:05:58 2007 Subject: patch applied (haskell-prime-report): Change front matter to say " Haskell Prime" rather than " Haskell 98" . Message-ID: <20070108150948.GA24594@cvs.haskell.org> Mon Jan 8 07:06:32 PST 2007 Malcolm.Wallace@cs.york.ac.uk * Change front matter to say "Haskell Prime" rather than "Haskell 98". M ./report/haskell.verb -5 +6 M ./report/intro.verb -1 +1 M ./report/preface-jfp.verb -53 +68 From ijones at syntaxpolice.org Thu Jan 11 20:05:41 2007 From: ijones at syntaxpolice.org (Isaac Jones) Date: Thu Jan 11 20:01:39 2007 Subject: patch applied (haskell-prime-report): update pattern binding translation for pattern guards (with Iavor' s help!) Message-ID: <20070112010541.GA19179@cvs.haskell.org> Thu Jan 11 15:51:14 PST 2007 ijones@syntaxpolice.org * update pattern binding translation for pattern guards (with Iavor's help!) M ./report/decls.verb -7 +9 From ijones at syntaxpolice.org Thu Jan 11 20:05:42 2007 From: ijones at syntaxpolice.org (Isaac Jones) Date: Thu Jan 11 20:01:40 2007 Subject: patch applied (haskell-prime-report): reworking the informal explanation of pattern gaurds Message-ID: <20070112010542.GA19199@cvs.haskell.org> Thu Jan 11 16:59:30 PST 2007 ijones@syntaxpolice.org * reworking the informal explanation of pattern gaurds Modified the syntax again to talk about "guards" (which are pattern guards, boolean guards, and let expressions) . Moved the "Pattern guards" section I created before into the Case Expressions section. M ./report/decls.verb -3 +4 M ./report/exps.verb -63 +71 From ijones at galois.com Fri Jan 12 19:55:55 2007 From: ijones at galois.com (isaac jones) Date: Fri Jan 12 19:51:53 2007 Subject: patch applied (haskell-prime-report): some notes on how to build it. In-Reply-To: References: <20070108111207.GA19065@cvs.haskell.org> Message-ID: <1168649755.15873.549.camel@localhost.localdomain> On Mon, 2007-01-08 at 13:42 +0000, David House wrote: > On 08/01/07, Simon Marlow wrote: > > Mon Jan 8 03:11:48 PST 2007 Simon Marlow > > * some notes on how to build it. > > > > M ./README -6 +26 > > Using the flex version 2.5.31, straight out of apt, I get the following error: > > flex -t -8 verbatim.lex > verbatim.c || ( rm -f verbatim.c && exit 1 ) > verbatim.lex:75: warning, rule cannot be matched > cc -c verbatim.c -o verbatim.o > :561:25: error: macro "yywrap" passed 1 arguments, but takes just 0 > make: *** [verbatim] Error 1 > > Using the flex-old package, which is version 2.5.4a, it works. I guess > this means our flex files are legacy. Could they be updated to work > with the latest flex? This has been fixed :) It turns out that not all mods are posted to the mailing list, due to subscription requirements. peace, isaac From ijones at galois.com Fri Jan 12 20:08:20 2007 From: ijones at galois.com (isaac jones) Date: Fri Jan 12 20:04:16 2007 Subject: pattern guards: recent changes to draft haskell prime report Message-ID: <1168650500.15873.558.camel@localhost.localdomain> Greetings! We've been working to add pattern guards to the Haskell' report, and doing some cleanup work on the repository. Not all of the emails are making it to the list, sadly, but here's a list of recent changes from the report. You can view the report itself here (I couldn't think of a good place to put it): http://hackage.haskell.org/~ijones/haskell-prime-report/report/haskell98-report-html/ peace, isaac Fri Jan 12 16:32:28 PST 2007 iavor.diatchki@gmail.com * moved rules for guards in a separate figure because the old figure didn't fit on a page Fri Jan 12 16:21:46 PST 2007 iavor.diatchki@gmail.com * fixed rule (g) of pattern semantics to avoid duplicating the evaluation of e' Fri Jan 12 16:13:50 PST 2007 iavor.diatchki@gmail.com * added rules for pattern guards to the formal semantics of case Fri Jan 12 14:53:30 PST 2007 iavor.diatchki@gmail.com * gneralized function bindings to support pattern guards, not just boolean guards Thu Jan 11 16:59:30 PST 2007 ijones@syntaxpolice.org * reworking the informal explanation of pattern gaurds Modified the syntax again to talk about "guards" (which are pattern guards, boolean guards, and let expressions) . Moved the "Pattern guards" section I created before into the Case Expressions section. Thu Jan 11 15:51:14 PST 2007 ijones@syntaxpolice.org * update pattern binding translation for pattern guards (with Iavor's help!) Mon Jan 8 10:21:14 PST 2007 Andres Loeh * turn macro into function -- makes it work with newer flex versions Mon Jan 8 09:50:40 PST 2007 Andres Loeh * don't include extension in \includegraphics (to make compatible with pdflatex) Mon Jan 8 09:20:29 PST 2007 Andres Loeh * typo: change \r to \tr From dmhouse at gmail.com Sun Jan 14 13:32:53 2007 From: dmhouse at gmail.com (David House) Date: Sun Jan 14 13:28:44 2007 Subject: patch applied (haskell-prime-report): some notes on how to build it. In-Reply-To: <1168649755.15873.549.camel@localhost.localdomain> References: <20070108111207.GA19065@cvs.haskell.org> <1168649755.15873.549.camel@localhost.localdomain> Message-ID: On 13/01/07, isaac jones wrote: > This has been fixed :) Great. I can now build the report successfully. -- -David House, dmhouse@gmail.com From Malcolm.Wallace at cs.york.ac.uk Mon Jan 15 09:55:32 2007 From: Malcolm.Wallace at cs.york.ac.uk (Malcolm Wallace) Date: Mon Jan 15 09:51:20 2007 Subject: patch applied (haskell-prime-report): Update lots of references to H' 98 -> Prime, especially in build system. Message-ID: <20070115145532.GA13374@cvs.haskell.org> Mon Jan 15 06:47:52 PST 2007 Malcolm.Wallace@cs.york.ac.uk * Update lots of references to H'98 -> Prime, especially in build system. I have taken the liberty of rejigging the build system somewhat, so that we can auto-generate the PDF/HTML version of the Language Report every time a patch is checked into darcs. M ./Makefile -3 +8 M ./README -12 +18 M ./report/Makefile -10 +11 M ./report/README -2 +2 R ./report/h98-revised.html R ./report/h98.gif A ./report/haskell-prime-draft.html R ./report/haskell98-bugs.html R ./report/haskell98-revised-bugs.html A ./report/hprime.png A ./report/hprime.ppt M ./report/html.config -6 +6 M ./report/index.html -7 +6 M ./tools/index.hs -1 +1 From Malcolm.Wallace at cs.york.ac.uk Mon Jan 15 10:06:50 2007 From: Malcolm.Wallace at cs.york.ac.uk (Malcolm Wallace) Date: Mon Jan 15 10:07:04 2007 Subject: recent changes to draft haskell prime report In-Reply-To: <1168650500.15873.558.camel@localhost.localdomain> References: <1168650500.15873.558.camel@localhost.localdomain> Message-ID: <20070115150650.6938f02d.Malcolm.Wallace@cs.york.ac.uk> isaac jones wrote: > You can view the report itself here (I couldn't think of a good place > to put it): > http://hackage.haskell.org/~ijones/haskell-prime-report/report/haskell98-report-html/ I have fiddled with the build system, to enable the current state of the Report in the darcs repository to be generated into (at least) HTML, (hopefully also PDF and PS soon) automatically as every patch is checked in. In theory, the following link should always give you the most up-to-date version of the text: http://darcs.haskell.org/haskell-prime-report/report/haskell-prime-draft.html (I am wondering whether to make this a 'darcs test' thing, so if the Report fails to build, your patch will be rejected. Any opinions?) Regards, Malcolm From dons at cse.unsw.edu.au Mon Jan 15 10:16:11 2007 From: dons at cse.unsw.edu.au (Donald Bruce Stewart) Date: Mon Jan 15 10:12:09 2007 Subject: recent changes to draft haskell prime report In-Reply-To: <20070115150650.6938f02d.Malcolm.Wallace@cs.york.ac.uk> References: <1168650500.15873.558.camel@localhost.localdomain> <20070115150650.6938f02d.Malcolm.Wallace@cs.york.ac.uk> Message-ID: <20070115151611.GA14174@cse.unsw.EDU.AU> Malcolm.Wallace: > isaac jones wrote: > > > You can view the report itself here (I couldn't think of a good place > > to put it): > > http://hackage.haskell.org/~ijones/haskell-prime-report/report/haskell98-report-html/ > > I have fiddled with the build system, to enable the current state of the > Report in the darcs repository to be generated into (at least) HTML, > (hopefully also PDF and PS soon) automatically as every patch is checked > in. In theory, the following link should always give you the most > up-to-date version of the text: > > http://darcs.haskell.org/haskell-prime-report/report/haskell-prime-draft.html > > (I am wondering whether to make this a 'darcs test' thing, so if the > Report fails to build, your patch will be rejected. Any opinions?) That seems reasonable. -- Don From loeh at iai.uni-bonn.de Mon Jan 15 10:57:22 2007 From: loeh at iai.uni-bonn.de (Andres Loeh) Date: Mon Jan 15 10:45:50 2007 Subject: recent changes to draft haskell prime report In-Reply-To: <20070115150650.6938f02d.Malcolm.Wallace@cs.york.ac.uk> References: <1168650500.15873.558.camel@localhost.localdomain> <20070115150650.6938f02d.Malcolm.Wallace@cs.york.ac.uk> Message-ID: <20070115155722.GE4697@iai.uni-bonn.de> > I have fiddled with the build system, to enable the current state of the > Report in the darcs repository to be generated into (at least) HTML, > (hopefully also PDF and PS soon) automatically as every patch is checked do we still need PS? > in. In theory, the following link should always give you the most > up-to-date version of the text: > > http://darcs.haskell.org/haskell-prime-report/report/haskell-prime-draft.html > > (I am wondering whether to make this a 'darcs test' thing, so if the > Report fails to build, your patch will be rejected. Any opinions?) Good idea. Cheers, Andres From Malcolm.Wallace at cs.york.ac.uk Mon Jan 15 10:55:52 2007 From: Malcolm.Wallace at cs.york.ac.uk (Malcolm Wallace) Date: Mon Jan 15 10:56:19 2007 Subject: defaults In-Reply-To: References: <20061121093333.5923ed8d.Malcolm.Wallace@cs.york.ac.uk> Message-ID: <20070115155552.03b8e050.Malcolm.Wallace@cs.york.ac.uk> Simon Marlow wrote: > Is your proposal supposed to be backwards compatible with Haskell 98 > for programs that don't have default declarations? Yes, it is supposed to be backwards compatible. > If so, then I offer a counter example: > toRational pi > will default pi to Double in Haskell 98, but will be an error under > your proposal, because the two constraints (Real and Floating) > disagree on the default. Well spotted. So there are some expressions that are defaulted in H'98 but would not pass type-checking with my proposal. (1) Are examples like this common? I am guessing not. You mention Enum/Fractional combinations, but arguably Float and Double do not belong in Enum anyway. (2) The new rule is conservative - it does not silently change the semantics, but it does reject more programs. Such programs are easily fixed by adding a type signature. If these two points are valid, then I think the slight loss of backward compatibility is acceptable? Regards, Malcolm From simonmar at microsoft.com Tue Jan 16 08:54:39 2007 From: simonmar at microsoft.com (Simon Marlow) Date: Tue Jan 16 08:50:26 2007 Subject: defaults In-Reply-To: <20070115155552.03b8e050.Malcolm.Wallace@cs.york.ac.uk> References: <20061121093333.5923ed8d.Malcolm.Wallace@cs.york.ac.uk> <20070115155552.03b8e050.Malcolm.Wallace@cs.york.ac.uk> Message-ID: haskell-prime-bounces@haskell.org wrote: > Simon Marlow wrote: > >> Is your proposal supposed to be backwards compatible with Haskell 98 >> for programs that don't have default declarations? > > Yes, it is supposed to be backwards compatible. > >> If so, then I offer a counter example: >> toRational pi >> will default pi to Double in Haskell 98, but will be an error under >> your proposal, because the two constraints (Real and Floating) >> disagree on the default. > > Well spotted. So there are some expressions that are > defaulted in H'98 > but would not pass type-checking with my proposal. > > (1) Are examples like this common? I am guessing not. You mention > Enum/Fractional combinations, but arguably Float and > Double do not > belong in Enum anyway. > > (2) The new rule is conservative - it does not silently change the > semantics, but it does reject more programs. Such programs are > easily fixed by adding a type signature. > > If these two points are valid, then I think the slight loss > of backward compatibility is acceptable? I don't know whether this is an acceptable loss of backwards compatibility, perhaps it is. But I spotted the problem because it looks (to me) like the current Haskell 98 rule is designed specifically to handle cases like this. Would you mind updating the wiki page? I don't think it's too clear on the need for constraint simplification before applying your defaulting rules either. Cheers, Simon From Malcolm.Wallace at cs.york.ac.uk Tue Jan 16 12:17:13 2007 From: Malcolm.Wallace at cs.york.ac.uk (Malcolm Wallace) Date: Tue Jan 16 12:16:29 2007 Subject: defaults In-Reply-To: References: <20061121093333.5923ed8d.Malcolm.Wallace@cs.york.ac.uk> <20070115155552.03b8e050.Malcolm.Wallace@cs.york.ac.uk> Message-ID: <20070116171713.5469f921.Malcolm.Wallace@cs.york.ac.uk> Simon Marlow wrote: > >> If so, then I offer a counter example: > >> toRational pi > > > > If these two points are valid, then I think the slight loss > > of backward compatibility is acceptable? > > I spotted the problem because it > looks (to me) like the current Haskell 98 rule is designed > specifically to handle cases like this. I agree that having to write toRational (pi::Double) is somewhat ugly. > Would you mind updating the wiki page? I don't think it's too clear > on the need for constraint simplification before applying your > defaulting rules either. I have added your counter example to the wiki. But I'm not sure how to make the need for constraint simplification clearer. 3 out of the 7 sentences in the proposal describe it, and 3 out of the 5 examples mention its role. What do you think is missing? Regards, Malcolm From ijones at syntaxpolice.org Fri Jan 19 18:51:05 2007 From: ijones at syntaxpolice.org (Isaac Jones) Date: Fri Jan 19 18:46:38 2007 Subject: patch applied (haskell-prime-report): pattern_guard_list_comprehension_footnote Message-ID: <20070119235105.GA15990@cvs.haskell.org> Fri Jan 19 15:23:01 PST 2007 'Ravi Nanavati ' * pattern_guard_list_comprehension_footnote M ./report/exps.verb -1 +3 From iavor.diatchki at gmail.com Sun Jan 21 17:25:35 2007 From: iavor.diatchki at gmail.com (Iavor Diatchki) Date: Sun Jan 21 17:21:03 2007 Subject: Polymorphic Components Message-ID: <5ab17e790701211425j347203b7td898e434d8bb767b@mail.gmail.com> Hello, I have written some notes about changes to Haskell 98 that are required to add the "polymorphic components" extension. The purpose of the notes is to enumerate all the details that need to be specified in the Haskell report. I don't have access to the haskell-prime wiki so I attached the notes to the ticke for polymorphic components: http://hackage.haskell.org/trac/haskell-prime/ticket/57 When there are different ways to do things I have tried to enumerate the alternatives and the PROPOSAL paragraph marks the choice that I favor. -Iavor From droundy at darcs.net Mon Jan 22 15:13:35 2007 From: droundy at darcs.net (David Roundy) Date: Mon Jan 22 15:12:12 2007 Subject: [Haskell] Views in Haskell In-Reply-To: References: Message-ID: <20070122201333.GD30099@abridgegame.org> On Mon, Jan 22, 2007 at 02:57:27PM +0000, Simon Peyton-Jones wrote: > Dear Haskellers > > Provoked by a discussion with Don Syme, and after some helpful > conversations at POPL, I have finally written up a proposal for adding > "view patterns" to Haskell. We've wanted views for a long time, but they > have never made it, into GHC at any rate. This proposal is a very > lightweight (and hence, I hope, cost-effective) proposal for a view-like > mechanism. > > http://hackage.haskell.org/trac/haskell-prime/wiki/ViewPatterns > > I'm thinking of implementing it in GHC, so I'd be interested in feedback of the form > - how desirable is it to have a feature of this general form? > - can this particular proposal be improved? It looks pretty cool to me, and simple enough to be reasonable. One feature that would be particularly interesting would be to add some sort of annotation mechanism to describe a possible "complete" set of views (with respect to improving warnings about inexhaustive pattern matching). I wonder if you could have something like: data Foo = FooBar Bar | FooBaz Baz foobar :: Foo -> Maybe Bar foobaz :: Foo -> Maybe Baz {-# COMPREHENSIVE_VIEWS Foo : foobar, foobaz #-} which tells the compiler that for any Foo, one of foobar and foobaz will return a non-Nothing result. It'd allow us--at least in the simple views case--to retain the existing level of warnings, and ought also to be useful in somewhat trickier case as well. Another idea is whether the syntax could be extended to indicate a failure to match? This would actually be useful even without views, but it's particularly useful with views (and especially so in the context of the above warnings). I'd imagine something like (with stupidly chosen syntax of !!!) foo (_:_) = True foo _ = False foo' !!![] = True foo' _ = False Here I've defined two identical functions to describe what I mean by "!!!". I didn't gain anything in this case, but might gain some clarity if there are multiple constructors. But more to the point, if we're using views (of the vanilla Maybe-always variety), we could gain some efficiency this way. foo ([], view -> a, []) = foo1 a foo (x, !!! view ->, []) = foo2 x foo (_, view -> a, y) = foo3 a y This isn't a very good example, but the point is I'd like to be able to match on Nothing and get the same benefits you mention about the compiler being assumed to optimize by calling view only once. We could achieve this by reordering the patterns, but I believe (although I failed to come up with one above) that there are sets of pattern matches that aren't reducible in that way, which it'd be nice to be able to express succinctly by matching on failure to match a pattern. Maybe this should be foo (x, view /->, []) = foo2 x or something like that, to indicate failure, that view doesn't match? -- David Roundy Department of Physics Oregon State University _______________________________________________ Haskell mailing list Haskell@haskell.org http://www.haskell.org/mailman/listinfo/haskell From simonpj at microsoft.com Tue Jan 23 04:09:07 2007 From: simonpj at microsoft.com (Simon Peyton-Jones) Date: Tue Jan 23 04:04:30 2007 Subject: [Haskell] Views in Haskell In-Reply-To: References: Message-ID: [Redirecting to haskell-prime] | In the related work, the "Active Patterns" proposal by Palao et at is missing: | | http://portal.acm.org/citation.cfm?id=232641&coll=portal&dl=ACM | | I thought this work should be included in the list because, I believe, | they were the first to point out that computation should take place | before matching, which was not the case in Wadler's and Burton's | proposals? They also proposed types for patterns. Good point. I've added them. I think the Wadler/Burton stuff did allow for arbitrary computation; it's just that there was no way to do the value-input thing. (Pattern synonyms, on the other hand, do not.) Simon From claus.reinke at talk21.com Tue Jan 23 10:07:08 2007 From: claus.reinke at talk21.com (Claus Reinke) Date: Tue Jan 23 10:02:34 2007 Subject: [Haskell] Views in Haskell References: Message-ID: <008301c73f00$28887590$12528351@cr3lt> > http://hackage.haskell.org/trac/haskell-prime/wiki/ViewPatterns > >I'm thinking of implementing it in GHC, so I'd be interested in feedback of the form > - how desirable is it to have a feature of this general form? > - can this particular proposal be improved? IMHO, getting a handle on the ADT vs pattern matching issues is overdue, so thanks for raising this again. a few first comments: 1 I am a bit concerned about the use of non-linear patterns in your examples. There are good arguments for non-linear patterns, and Haskellers have made good arguments against non-linear patterns. But you seem to suggest allowing non-linear patterns in some cases (related to view patterns), but not in others (general patterns). That is likely to be confusing. 2 view patterns nicely separate expressions in patterns from pattern variables. But I didn't realize at first that view patterns can be used nested inside other patterns. Yet this variable binding during nested matching is the essential contribution, and the only reason why the extra syntactic sugar is justified. Perhaps this point could be repeated and emphasized in "The proposal more formally", for people like me?-) 3 what you call first class abstractions are not entirely orthogonal to view patterns. taking Tullsen's and my own proposal as examples: - the way patterns and alternatives are handled needs to fit together. that doesn't seem to be a problem since your and our proposals agree on using what I call a monadic data parsing framework (using a MonadPlus such as Maybe to handle pattern match failure and alternatives) - all three proposals have discussed how to handle patterns as well. For Tullsen, that is central to his proposal, for me, it was only one of the more advanced examples because I wanted to focus on match alternatives first. Tullsen first builds his pattern combinators, then outlines a point-free style that avoids the need for pattern variables althogether but does not seem to scale well, then suggests syntactic sugar for translating patterns with variables into applications of his combinators. So that last part is closely related to, if different from, your proposal. In my example, I build up patterns from de-constructors (which use tests and selectors), so that a cons pattern takes a head pattern and a tail pattern as parameters and applies them to the head and tail if it is applied to a non-empty list. To handle variables, I use an old trick from the early functional logic languages, namely that logic variables can be passed unbound, then bound to values later, just what we need for pattern variables. Since Haskell doesn't have logic variables, I have to simulate them, which is the only awkward bit of the example: http://www.haskell.org/pipermail/haskell-prime/2006-November/001915.html as long as Haskell doesn't support logic variables, some syntactic sugar for variables in nested patterns, such as Tullsen's or your's, is probably inevitable. 4 whether to use view patterns inside ordinary patterns, or whether to build up patterns from abstract de-constructors (just as expressions are built from abstract constructors) may seem only a question of style. but if your aim is to encourage people to transition from exporting concrete data types to exporting abstract types only, the latter approach seems more consistent to me. In my example, a cons de-constructor would be as simple as -- the cons view of array lists is a higher-order pattern that takes -- patterns for the head and tail components, and applies them after -- checking whether the list parameter is a non-empty list consAP h t l = do { Match $ guard $ not (isNilA l); h (headA l); t (tailA l) } but that relies on the scoping of (simulated) logic variables, and it does not translate directly to your view patterns, as the h and t pattern parameters would have their own scope for their pattern variables. It would be instructive to have something equivalent to pattern constructors/abstract deconstructors for view patterns, if only to see whether view patterns can support a fully abstract style of nested matches easily. I am not entirely sure they do, but here is a first attempt: -- abstract list deconstructors / list pattern constructors -- (consP takes h/t sub-patterns as parameters) consP h t l = do { guard $ not (null l); hr <- h (head l); tr <- t (tail l); return (hr,tr) } nilP l = do { guard $ null l; return () } -- wildcard and variable patterns wildP l = return () varP = return -- extract the head of the tail of the parameter list, if that list has two elements f (consP wildP (consP varP nilP) -> (_,(x,_))) = x It seems a bit awkward to have to specify the structure of the parameter twice, once to build up the pattern, then again to match sub-expressions to variables. but would this work in principle at least? 5 possible extension 1 smells of superfluous complexity. There is almost no gain compared to using tuples, but there's a lot to pay in added types and rules. 6 possible extension 2 seems a non-starter if we want compositional abstract patterns, and I certainly do want them. Imagine the example in (4) with explicit Maybe. Being able to have compositional abstract patterns would be the make-or-break criterion for me. Without them, new syntactic sugar wouldn't be justified, with them, their precise form is a matter of convenience. Claus From brianh at metamilk.com Tue Jan 23 23:15:49 2007 From: brianh at metamilk.com (Brian Hulley) Date: Tue Jan 23 23:10:01 2007 Subject: [Haskell] Views in Haskell References: Message-ID: <002501c73f6e$54affa80$09d52950@osmet> Simon Peyton-Jones wrote: > > http://hackage.haskell.org/trac/haskell-prime/wiki/ViewPatterns > > I'm thinking of implementing it in GHC, so I'd be interested in > feedback of the form > - how desirable is it to have a feature of this general form? > - can this particular proposal be improved? Regarding the syntax, I don't like the use of ->, because I think it is confusing to write even -> n when even is the function itself. In all other places in Haskell, A -> B represents a function from A to B whereas in the proposal A -> B represents the function A applied to the thing currently being matched which may return a value wrapped up in Maybe which matches B. There are 2 things - the inconsistent use of -> and the implicit Maybe. I'd rather the Maybe was not implicit (as described in extension 2), and a more consistent syntax was found. A possible syntax could represent the value being matched explicitly, say using ? to represent the value currently being matched, then the pattern could be written as an equation: f (prodSize ? = Small) = ... f (prodSize ? = Medium) = ... f (prodSize ? = Big) = ... or simulating an n + k pattern: g (? - 3 = n) = ... or a function which checks its arg satisfies an arbitrary expression: h (? - (3 * ?) = 10) = ... or an "n+k" against the second element of a list j ( toList ? = (_ : (? - 3 = n : _))) = ... Regarding the problem itself, I'm still not sure why views are needed. For example in (f) above, why not just write as: f :: Product -> ... f prod = k (prodSize prod) where k = ... Best regards, Brian. -- http://www.metamilk.com From dinko.tenev at gmail.com Wed Jan 24 05:02:48 2007 From: dinko.tenev at gmail.com (Dinko Tenev) Date: Wed Jan 24 04:58:07 2007 Subject: [Haskell] Views in Haskell In-Reply-To: <002501c73f6e$54affa80$09d52950@osmet> References: <002501c73f6e$54affa80$09d52950@osmet> Message-ID: On 1/24/07, Brian Hulley wrote: > > A possible syntax could represent the > value being matched explicitly, say using ? to represent the value > currently > being matched, then the pattern could be written as an equation: > > f (prodSize ? = Small) = ... > f (prodSize ? = Medium) = ... > f (prodSize ? = Big) = ... ...or maybe (Small = prodSize ?), etc., to be consistent with let bindings? -------------- next part -------------- An HTML attachment was scrubbed... URL: http://www.haskell.org/pipermail/haskell-prime/attachments/20070124/b4072d79/attachment.htm From brianh at metamilk.com Wed Jan 24 07:22:01 2007 From: brianh at metamilk.com (Brian Hulley) Date: Wed Jan 24 07:15:53 2007 Subject: [Haskell] Views in Haskell References: <002501c73f6e$54affa80$09d52950@osmet> Message-ID: <001d01c73fb2$406555e0$a4ff2950@osmet> On Wednesday, January 24, 2007 10:02 AM, Dinko Tenev wrote: > On 1/24/07, Brian Hulley wrote: >> A possible syntax could represent the >> value being matched explicitly, say using ? to represent the value >> currently >> being matched, then the pattern could be written as an equation: >> >> f (prodSize ? = Small) = ... >> f (prodSize ? = Medium) = ... >> f (prodSize ? = Big) = ... > ...or maybe (Small = prodSize ?), etc., to be consistent with let > bindings? I like it! Just to fix a minor error in one of my previous examples, and to show it in let-compatible form: -- "n+3" pattern matching against 2nd element j (_ : (n = ? - 3) : _ = toList ?) = ... Also, perhaps the "binding" could be optional for "True = ", so that: test (True = isAlpha ?) = ... could just be written as: test (isAlpha ?) = ... (The presence of '?' in the pattern is enough to specify that it's an "active" pattern) Here is another example, in current syntax and in "new" syntax: old (n + 3) | 0 < n = ... -- using idiosyncratic n+k pattern new (n = ? - 3) | 0 < n = ... -- rational reconstruction or new (n @ (0 < ?) = ? - 3) = ... -- moving guard into pattern Brian. -- http://www.metamilk.com From ross at soi.city.ac.uk Wed Jan 24 07:21:28 2007 From: ross at soi.city.ac.uk (Ross Paterson) Date: Wed Jan 24 07:16:55 2007 Subject: [Haskell] Views in Haskell In-Reply-To: References: Message-ID: <20070124122128.GB3473@soi.city.ac.uk> On Mon, Jan 22, 2007 at 02:57:27PM +0000, Simon Peyton-Jones wrote: > This proposal is a very lightweight (and hence, I hope, cost-effective) > proposal for a view-like mechanism. > > http://hackage.haskell.org/trac/haskell-prime/wiki/ViewPatterns This could be considered a generalization of field matching (minus the data constructor), so you'd presumably want similar syntax for the two. From claus.reinke at talk21.com Wed Jan 24 08:20:20 2007 From: claus.reinke at talk21.com (Claus Reinke) Date: Wed Jan 24 08:15:42 2007 Subject: [Haskell] Views in Haskell References: <008301c73f00$28887590$12528351@cr3lt> Message-ID: <007501c73fba$66c82c50$f3577ad5@cr3lt> > -- abstract list deconstructors / list pattern constructors > -- (consP takes h/t sub-patterns as parameters) > consP h t l = do { guard $ not (null l); hr <- h (head l); tr <- t (tail l); return (hr,tr) } > nilP l = do { guard $ null l; return () } > > -- wildcard and variable patterns > wildP l = return () > varP = return > > -- extract the head of the tail of the parameter list, if that list has two elements > f (consP wildP (consP varP nilP) -> (_,(x,_))) = x hmm, the above was probably guided too much by thinking about my own proposal (and this style could be translated back to it fairly easily, I think). the following would make better use of view patterns, and be a lot simpler: -- cons pattern/deconstructor consP l = do { guard $ not (null l); return (head l, tail l) } -- extract head of tail of two-element list f (consP -> (_, consP -> (x, []) ) ) = x btw, lambda-match and view patterns complement each other: - the sugar in lambda-match embeds classical matches in data parsing - the sugar in view patterns embeds data parsing in classical patterns In view of this, I was wondering: if you do not limit yourself to Maybe, but allow other MonadPlus instances, wouldn't that give you or-patterns? also, view patterns give us local guards: g ( xs@( guard . not . null -> () ) ) ys = xs++ys if we combine these two, we could presumably do things like using the list MonadPlus for backtracking matches, as proposed in some other functional languages (also assuming non-linearity of patterns here): select :: Eq a => a -> Map a b -> b select key ( toList -> ( (guard . (key==) ) ,value) ) = value claus From Rene_de_Visser at hotmail.com Wed Jan 24 14:49:06 2007 From: Rene_de_Visser at hotmail.com (Rene de Visser) Date: Wed Jan 24 14:50:23 2007 Subject: [Haskell] Views in Haskell References: Message-ID: In my opinion, views are going to make more Haskell more complicated, and from what I have seen so far, for little gain. Maybe a poll should be made to see what features the average Haskeller feels the most in need of. Or what their greatest problems are. Going by the traffic over the previous months, I think that class aliases or extensible records would be higher on most peoples lists than views. Rene. From simonpj at microsoft.com Wed Jan 24 15:10:34 2007 From: simonpj at microsoft.com (Simon Peyton-Jones) Date: Wed Jan 24 15:05:51 2007 Subject: Views in Haskell Message-ID: There's been lots of interesting feedback about the views proposal -- thank you. Many of the suggestions amount to plausible design alternatives. If I do all the editing, I'll just become a bottleneck, and I'm more than usually snowed-under at the moment. So I've moved the Wiki page to the GHC wiki, which is world-editable. It's here http://hackage.haskell.org/trac/ghc/wiki/ViewPatterns The wiki isn't a good place for to-and-fro debate, but it is a good way to capture design alternatives. If those with alternatives to propose would like to add them (in an even handed way needless to say) to the wiki page, that'd be good. Feel free to re-structure the text if that'd make it clearer. The big question is, as several people have observed, whether the (modest) gain is worth the (also modest) pain. If the proposal has merit, it is its extreme simplicity. There's no comparison with things like class aliases, which are a Much Bigger Deal on both those metrics. Simon From simonpj at microsoft.com Wed Jan 24 15:27:46 2007 From: simonpj at microsoft.com (Simon Peyton-Jones) Date: Wed Jan 24 15:23:02 2007 Subject: [Haskell] Views in Haskell In-Reply-To: <008301c73f00$28887590$12528351@cr3lt> References: <008301c73f00$28887590$12528351@cr3lt> Message-ID: | 1 I am a bit concerned about the use of non-linear patterns in your examples. | There are good arguments for non-linear patterns, and Haskellers have made good | arguments against non-linear patterns. But you seem to suggest allowing non-linear | patterns in some cases (related to view patterns), but not in others (general patterns). | That is likely to be confusing. I don't think view patterns are non-linear at all! They are just as linear as Haskell's existing patterns. Definitely no implicit use of equality, for example. | 2 view patterns nicely separate expressions in patterns from pattern variables. But I | didn't realize at first that view patterns can be used nested inside other patterns. | | Yet this variable binding during nested matching is the essential contribution, and | the only reason why the extra syntactic sugar is justified. Perhaps this point could | be repeated and emphasized in "The proposal more formally", for people like me?-) I've added a section called "Nesting". You can readily edit it (since I moved the page) to amplify if you think it would help. | 3 what you call first class abstractions are not entirely orthogonal to view patterns. | taking Tullsen's and my own proposal as examples: I'm afraid I don't follow this. I think they are entirely orthogonal. | 4 whether to use view patterns inside ordinary patterns, or whether to build up | patterns from abstract de-constructors (just as expressions are built from | abstract constructors) may seem only a question of style. but if your aim is | to encourage people to transition from exporting concrete data types to | exporting abstract types only, the latter approach seems more consistent | to me. Again, I didn't follow | 5 possible extension 1 smells of superfluous complexity. There is almost no gain | compared to using tuples, but there's a lot to pay in added types and rules. You may well be right. | 6 possible extension 2 seems a non-starter if we want compositional abstract | patterns, and I certainly do want them. Imagine the example in (4) with | explicit Maybe. | | Being able to have compositional abstract patterns would be the make-or-break | criterion for me. Without them, new syntactic sugar wouldn't be justified, with | them, their precise form is a matter of convenience. I think I must be missing what you mean by a "compositional abstract pattern". Simon From claus.reinke at talk21.com Wed Jan 24 17:19:28 2007 From: claus.reinke at talk21.com (Claus Reinke) Date: Wed Jan 24 17:14:50 2007 Subject: [Haskell] Views in Haskell References: <008301c73f00$28887590$12528351@cr3lt> Message-ID: <017b01c74005$b7aef860$f3577ad5@cr3lt> >I don't think view patterns are non-linear at all! They are just as linear as Haskell's >existing patterns. Definitely no implicit use of equality, for example. interesting point. the left-hand sides are non-linear, in that variables may appear several times, but the context distinguishes between pattern-variables and expression variables in view patterns, and the parts concerned with matching are linear, so every pattern-variable will still only have a single point of definition. perhaps that is sufficient to avoid confusion. but the idea that bindings have a left to right bias is new to Haskell patterns, and switching formal and actual parameters can now be statically different, not just dynamically different. Unless the plan is to treat the following two as equivalent? let { f1 p (p -> ()) = () } in f1 return () let { f2 (p -> ()) p = () } in f2 () return >I've added a section called "Nesting". it certainly makes the point. the part I didn't get at once was that I can build up abstract patterns from view patterns as I would build up abstract data from abstract constructors, and still be able to bind sub-structures to variables. >| 3 what you call first class abstractions are not entirely orthogonal to view patterns. >| taking Tullsen's and my own proposal as examples: >I'm afraid I don't follow this. I think they are entirely orthogonal. true first-class patterns, in whatever form, include the functionality provided by view patterns as a subset. only the syntax differs, and the means of variable binding. since we are aiming for a smooth integration with the rest of current Haskell, these differences are important, but they don't make the approaches orthogonal. Tullsen has the pattern binder construct (Section 4.1), which includes the ability to apply any pattern function (functions of type a->Maybe b) anywhere inside a pattern using the % construct. The result is matched against a pattern, which can be a variable. which covers the two aspects of view patterns. and as I've shown for the lambda-match library, one can compose pattern functions in the same way as one builds up a pattern from constructors, ie every part of the pattern is a pattern function. since I don't have syntactic sugar for variable binding, that second aspect of view patterns is a little more awkward. but it can be done in at least two ways, using the logic variable emulation I showed, or something similar to the result of Tullsen's translation of pattern binders. again covering both aspects of view patterns, without additional extensions. >| 4 whether to use view patterns inside ordinary patterns, or whether to build up >| patterns from abstract de-constructors (just as expressions are built from >| abstract constructors) may seem only a question of style. but if your aim is >| to encourage people to transition from exporting concrete data types to >| exporting abstract types only, the latter approach seems more consistent >| to me. >Again, I didn't follow I wasn't very clear, as I was still trying to get a handle on what view patterns can do. Sorry about that. Perhaps my second mail has already clarified my misconception, but let me try again: concrete data structures are built from concrete data constructors. concrete patterns are built from concrete data constructors (which thereby double as data de-constructors). abstract data structures are built from abstract data constructors, hiding the concrete representation. abstract patterns are built from abstract data-deconstructors (in our current context, that means pattern functions of type a -> Maybe b, for some a,b). my concern was whether it makes sense to use view patterns as abstract de-constructors inside otherwise concrete patterns, or whether one should encourage a wholesale switch to abstract patterns. as long as I can do the latter, I don't mind if the former is also possible. >I think I must be missing what you mean by a "compositional abstract pattern". most of the examples suggested that view patterns are used one a case by case basis, to select components from an adt part of a parameter. the alternative I'm aiming for, as exhibited in the consP example, would be to build patterns systematically from view patterns used as abstract de-constructors, composed in the same way as one would compose the abstract constructors to build the abstract data structure. in other words, you define your pattern constructors once, with the adt, and export them; and anytime you want to match somethind of that abstract type, you simply compose your pattern from those abstract pattern constructors. is that clearer? Claus From flippa at flippac.org Wed Jan 24 18:39:32 2007 From: flippa at flippac.org (Philippa Cowderoy) Date: Wed Jan 24 18:36:52 2007 Subject: [Haskell] Views in Haskell In-Reply-To: <017b01c74005$b7aef860$f3577ad5@cr3lt> References: <008301c73f00$28887590$12528351@cr3lt> <017b01c74005$b7aef860$f3577ad5@cr3lt> Message-ID: On Wed, 24 Jan 2007, Claus Reinke wrote: > the alternative I'm aiming for, as exhibited in the consP example, would be > to build patterns systematically from view patterns used as abstract > de-constructors, composed in the same way as one would compose the > abstract constructors to build the abstract data structure. in other words, > you define your pattern constructors once, with the adt, and export them; > and anytime you want to match somethind of that abstract type, you simply > compose your pattern from those abstract pattern constructors. > This would cause an awful lot of kludging to get around the fact you need to declare a new ADT to declare new abstract deconstructors, and requires an additional extension for abstract deconstructors to be typeclass methods - something abstract constructors can do for free. Neither seems gainful to me. -- flippa@flippac.org Performance anxiety leads to premature optimisation From tullsen at galois.com Wed Jan 24 19:54:13 2007 From: tullsen at galois.com (Mark Tullsen) Date: Wed Jan 24 19:49:47 2007 Subject: [Haskell] Views in Haskell Message-ID: Sorry to enter the discussion a little late ... First, I'm not clear what Simon meant by "first class abstractions" in this comment > Several proposals suggest first class abstractions rather that > first-class patterns. Here are the ones I know of ... Second, I completely agree with Claus in his comment here that my "First Class Patterns" paper is definitely related to, and not orthogonal to view patterns: The "big idea" of my paper was to stop the growing complexity of the pattern-language of Haskell. The idea was to use the abstraction capabilities of the language along with some simple syntactic sugar to give us 'pattern omnipotence'. However, my approach could be seen as orthogonal in that I did not propose to change Haskell patterns. Instead, I suggested some additional syntax that could serve as a replacement for complicated uses of patterns. Strangely, for other reasons, I'm planning, within a week or so, to start implementing the "pattern-binder" syntax I discussed in the paper (either in GHC or as a pre-processor). - Mark Claus Reinke wrote: > 3 what you call first class abstractions are not entirely > orthogonal to view patterns. > taking Tullsen's and my own proposal as examples: > > - the way patterns and alternatives are handled needs to fit > together. that doesn't > seem to be a problem since your and our proposals agree on > using what I call > a monadic data parsing framework (using a MonadPlus such as > Maybe to handle > pattern match failure and alternatives) > > - all three proposals have discussed how to handle patterns as > well. For Tullsen, > that is central to his proposal, for me, it was only one of the > more advanced > examples because I wanted to focus on match alternatives first. > > Tullsen first builds his pattern combinators, then outlines a > point-free style that > avoids the need for pattern variables althogether but does not > seem to scale well, > then suggests syntactic sugar for translating patterns with > variables into applications > of his combinators. So that last part is closely related to, if > different from, your > proposal. > > In my example, I build up patterns from de-constructors (which > use tests and > selectors), so that a cons pattern takes a head pattern and a > tail pattern as > parameters and applies them to the head and tail if it is > applied to a non-empty > list. To handle variables, I use an old trick from the early > functional logic > languages, namely that logic variables can be passed unbound, > then bound to > values later, just what we need for pattern variables. Since > Haskell doesn't > have logic variables, I have to simulate them, which is the > only awkward bit > of the example: > http://www.haskell.org/pipermail/haskell-prime/2006-November/ > 001915.html > > as long as Haskell doesn't support logic variables, some syntactic > sugar for > variables in nested patterns, such as Tullsen's or your's, is > probably inevitable. From john at repetae.net Wed Jan 24 20:22:30 2007 From: john at repetae.net (John Meacham) Date: Wed Jan 24 20:17:49 2007 Subject: Views in Haskell In-Reply-To: References: Message-ID: <20070125012230.GJ8540@momenergy.repetae.net> I am having a hard time figuring out what views gain you, if anything. If you know from the start you want abstract deconstructors, then you can do that now and it has never been an issue, just mechanical and verbose: > date Term = Ap Term Term | Let Id Term Term > > fromAp :: Term -> Maybe (Term,Term) > fromAp (Ap a b) = Just (a,b) > fromAp _ = Nothing > > > foo t | Just (a,b) <- fromAp t = ... now views give you some (perhaps) nicer syntax for matching these sort of functions, but they don't make declaring them any less mechanical and verbose, but more importantly, you still have to know a priori whether you will need abstract deconstructors or not. the issue that needs to be solved is letting you extend pattern matching "after the fact", if you know you want abstract deconstructors from the beginning, then views don't make much difference, if you don't and want to seamlessly extend an existing type, then you are out of luck, views or not. John -- John Meacham - ?repetae.net?john? From tullsen at galois.com Thu Jan 25 01:48:18 2007 From: tullsen at galois.com (Mark Tullsen) Date: Thu Jan 25 01:43:56 2007 Subject: [Haskell] Views in Haskell In-Reply-To: References: Message-ID: <3892CDA7-455B-4546-AC06-204A9F1A1C40@galois.com> On Jan 22, 2007, at 6:57 AM, Simon Peyton-Jones wrote: > I'm thinking of implementing it in GHC, so I'd be interested in feedback of the form > - how desirable is it to have a feature of this general form? While it looks like a useful extension with a lot of bang for the buck, I think I'd prefer to live without it; two reasons: 1) I'm a minimalist 2) I find that using my pattern combinators (http://citeseer.ist.psu.edu/tullsen00first.html) and do-notation I get by very well without using any of the advanced features of patterns. OK, I guess I'm a little biased. > - can this particular proposal be improved? I definitely agree with Claus's comment: > 5 possible extension 1 smells of superfluous complexity. There is almost no gain > compared to using tuples, but there's a lot to pay in added types and rules.m From simonpj at microsoft.com Thu Jan 25 03:42:18 2007 From: simonpj at microsoft.com (Simon Peyton-Jones) Date: Thu Jan 25 03:37:36 2007 Subject: [Haskell] Views in Haskell In-Reply-To: References: Message-ID: | First, I'm not clear what Simon meant by "first class abstractions" | in this comment | | > Several proposals suggest first class abstractions rather that | > first-class patterns. Here are the ones I know of ... Sorry to have been un-clear. By a "first class abstraction" I mean a value of type something -> something with a syntax something like \ pattern -> body The abstraction includes both the pattern and the result. In contrast, view patterns tackle only the syntax of patterns; the pattern of a first-class abstraction. I'll update the wiki A first-class *pattern*, on the other hand, really ought to be something like (a,b), where a and b are *binders*. This is what Barry Jay means by a first-class pattern in his very interesting work (which I should reference from the wiki). See "The Patten Calculus" http://www-staff.it.uts.edu.au/~cbj/Publications/chronological.html Still, I think it's likely that I'm exaggerating, and that view patterns and first-class abstractions are tied up together somehow. But I don't grok exactly how. Simon From simonpj at microsoft.com Thu Jan 25 03:55:39 2007 From: simonpj at microsoft.com (Simon Peyton-Jones) Date: Thu Jan 25 03:50:56 2007 Subject: [Haskell] Views in Haskell In-Reply-To: <017b01c74005$b7aef860$f3577ad5@cr3lt> References: <008301c73f00$28887590$12528351@cr3lt> <017b01c74005$b7aef860$f3577ad5@cr3lt> Message-ID: | is that clearer? yes, thanks. I'm not quite sure whether it all means you think view patterns are good; or that they would be good with a tweak; or that something else would be better. Do feel free to edit the wiki to articulate any design alternatives that you think deserve consideration. Regardless of whether any of this gets implemented, I think the wiki page can usefully summarise a description of at least a local part of the design space. Simon From claus.reinke at talk21.com Thu Jan 25 06:49:21 2007 From: claus.reinke at talk21.com (Claus Reinke) Date: Thu Jan 25 06:44:41 2007 Subject: [Haskell] Views in Haskell References: <008301c73f00$28887590$12528351@cr3lt> <017b01c74005$b7aef860$f3577ad5@cr3lt> Message-ID: <006301c74076$dbc72ad0$513e7ad5@cr3lt> >I'm not quite sure whether it all means you think view patterns are good; or that >they would be good with a tweak; or that something else would be better. probably because my opinion has been changing;-) at first, I wasn't convinced, now I think it depends on the details. as Mark said, such syntactic extensions of conventional patterns are not strictly necessary since we know how to avoid them completely (using data parsing). so for a new functional language, I too would like to drop patterns as built-ins, providing their functionality via sugar and libraries. but as far as Haskell is concerned, I am perhaps less radical in my approach than Mark is: Haskellers have invested an awful lot of work in those conventional patterns, in readibility, in optimisations, and in linking them with other extensions (eg., type system extensions). that is why I proposed the lambda-match construct to complement the library Control.Monad.Match, so that conventional patterns could be used within the data parsing framework. and that is why I think view patterns are useful: they allow us to embed data parsing into conventional patterns, reusing existing syntax for binding pattern variables while still allowing us to define our own pattern constructors. so I'd like to have both lambda-match and view patterns, supported by Control.Monad.Match, and well integrated. but if suggestions to make Maybe explicit in view patterns, or to drop it alltogether, carry the day, I might lose interest. also, I'd like the syntax to stay close to conventional constructors, rather than close to pattern guards. regarding first-class abstractions/terminology: for myself, I have settled on using "first-class matches" (or "first-class match alternatives") for the likes of the lambda-match construct (left-hand side pattern, right-hand side expression), and "first-class patterns" for proposals that actually allow to abstract over the left-hand sides of matches. both first-class matches and first-class patterns tend to use the common framework of MonadPlus instances for match failure and fall-through, as a generalisation of the good old monadic combinator parsers on strings. for this framework I use the term "monadic data parsing". regarding syntax for view patterns: I like the prefix form, but agree that the use of "->" is unfortunate. If it wasn't for pattern constants, I'd probably just use application (lower case identifiers in function position in a pattern can only be views, unless someone suggests other uses for that syntax; and the last parameter of a view has to be a pattern). The next best thing, to emphasize that we're essentially computing patterns, would be to borrow TH's notation for splicing, using $(view p1..pn) pattern instead of view p1..pn -> pattern Claus From claus.reinke at talk21.com Thu Jan 25 09:40:58 2007 From: claus.reinke at talk21.com (Claus Reinke) Date: Thu Jan 25 09:36:17 2007 Subject: [Haskell] Views in Haskell References: Message-ID: <019301c7408e$d4d71e70$513e7ad5@cr3lt> > Strangely, for other reasons, I'm planning, within a week or so, to > start implementing the "pattern-binder" syntax I discussed in the paper > (either in GHC or as a pre-processor). I'm somewhat surprised to read this. Between view patterns, lambda-match, and Control.Monad.Match, I thought we were approaching a situation in which we have all the essential aspects covered (perhaps apart from the fact that your combinators come in both left-right and right-left variants), with slightly more convenience and better integration with existing pattern match facilities Especially the pattern-binder syntax and translation strike me as more complicated (so much so that I would rather use a simplified form of the translation result than all that machinery) and no more general than combining view patterns with pattern functions. But perhaps that is a question of personal style (and my own use of type-classes to lift mplus to pattern-functions has also been classed as complicated by others;-). Is there anything specific you find missing, or a those other reasons the motivation with going for your own version? Claus From tullsen at galois.com Thu Jan 25 11:49:04 2007 From: tullsen at galois.com (Mark Tullsen) Date: Thu Jan 25 11:44:40 2007 Subject: [Haskell] Views in Haskell In-Reply-To: <006301c74076$dbc72ad0$513e7ad5@cr3lt> References: <008301c73f00$28887590$12528351@cr3lt> <017b01c74005$b7aef860$f3577ad5@cr3lt> <006301c74076$dbc72ad0$513e7ad5@cr3lt> Message-ID: On Jan 25, 2007, at 3:49 AM, Claus Reinke wrote: > but as far as Haskell is concerned, I am perhaps less radical in my > approach than Mark is: Haskellers have invested an awful lot of > work in those conventional patterns, in readibility, in > optimisations, and in linking them with other extensions (eg., type > system extensions). I actually would agree. The purist in me would want to use a language with a simple exhaustive case construct and pattern-binders and no more; but the pragmatist in me does, usually, go with the flow of the language and use some of the more complex pattern-matching constructs. However, I did edit the web page to include an improved description of First Class Patterns, for a point of reference and comparison. - Mark From tullsen at galois.com Thu Jan 25 14:44:16 2007 From: tullsen at galois.com (Mark Tullsen) Date: Thu Jan 25 14:39:47 2007 Subject: [Haskell] Views in Haskell In-Reply-To: <019301c7408e$d4d71e70$513e7ad5@cr3lt> References: <019301c7408e$d4d71e70$513e7ad5@cr3lt> Message-ID: <86910C0C-B6C4-4268-9B8E-97B775491B27@galois.com> On Jan 25, 2007, at 6:40 AM, Claus Reinke wrote: >> Strangely, for other reasons, I'm planning, within a week or so, >> to start implementing the "pattern-binder" syntax I discussed in >> the paper (either in GHC or as a pre-processor). > > I'm somewhat surprised to read this. Between view patterns, lambda- > match, > and Control.Monad.Match, I thought we were approaching a situation in > which we have all the essential aspects covered (perhaps apart from > the fact that your combinators come in both left-right and right- > left variants), with slightly more convenience and better > integration with existing pattern match facilities > Especially the pattern-binder syntax and translation strike me as more > complicated (so much so that I would rather use a simplified form > of the translation result than all that machinery) and no more > general than combining view patterns with pattern functions. But > perhaps that is a > question of personal style (and my own use of type-classes to lift > mplus to pattern-functions has also been classed as complicated by > others;-). > > Is there anything specific you find missing, or a those other > reasons the > motivation with going for your own version? > > Claus > Good question. It's not that I think there is some "essential aspect" which isn't covered: View patterns will definitely add some useful expressiveness, and ditto for lambda-match and Control.Monad.Match (though I haven't yet had time to fully assimilate this stuff: I didn't start following this thread till yesterday). First Class Patterns are radical enough and are so far from meshing with the pattern language of Haskell that I don't really consider them a "competing proposal". My motivations for implementing "pattern-binder" syntax are as follows 1) I have a special need for some significant syntactic sugar for which pattern binders perfectly fit the bill. (For general programming I use my pattern combinators and the 'do' notation.) 2) There are other reasons why I want to use Haskell-98 and would like to be able to use other compilers. Thus, I'd want a pattern-binder preprocessor (extending GHC is not as important to me). Here's my motivating example. Here's a fragment for an STG interpreter in Haskell-98: {{{ rule_CASE_ELIM (Case p alts, s, h, o) = do ConApp c as <- ptsTo p h let matchAlt (Alt c' vs e) | c == c' = Just (vs,e) matchAlt _ = Nothing (vs,e) <- matchFirst matchAlt alts return (e `sub` (vs,as), s, h, o) }}} I'd like it to have a textual form just a little more abstract, I can do that with pattern binders and some appropriate combinators: {{{ rule_CASE_ELIM = { (Case p alts , s, h, o) } &&& ptsTo p h === { ConApp c as } &&& alts === matchFirst { Alt #c vs e } .-> (e `sub` (vs,as), s, h, o) }}} I'll leave it as an exercise to figure out how the last is parenthesized ;-). - Mark From ijones at galois.com Thu Jan 25 17:39:01 2007 From: ijones at galois.com (isaac jones) Date: Thu Jan 25 17:34:16 2007 Subject: help from the community? In-Reply-To: <5ab17e790701211425j347203b7td898e434d8bb767b@mail.gmail.com> References: <5ab17e790701211425j347203b7td898e434d8bb767b@mail.gmail.com> Message-ID: <1169764741.5904.138.camel@localhost.localdomain> On Sun, 2007-01-21 at 14:25 -0800, Iavor Diatchki wrote: > Hello, > > I have written some notes about changes to Haskell 98 that are > required to add the "polymorphic components" extension. The purpose > of the notes is to enumerate all the details that need to be specified > in the Haskell report. I don't have access to the haskell-prime wiki > so I attached the notes to the ticke for polymorphic components: > http://hackage.haskell.org/trac/haskell-prime/ticket/57 > > When there are different ways to do things I have tried to enumerate > the alternatives and the PROPOSAL paragraph marks the choice that I > favor. Does anyone have any feedback on this work? The critical path for Haskell', at this point, is writing these bits of the report and having them validated by the community. But no one has read and commented on these topics: - Plans for changes to the report relating to Polymorphic Components - Draft changes to the report for pattern guards I understand that taking the time to pour over the report is a bit hard, but we desperately need people who are willing to do so if we're going to make progress. I think Iavor and I will start to make these changes tomorrow; does anyone have feedback before then? peace, isaac From dons at cse.unsw.edu.au Thu Jan 25 19:52:16 2007 From: dons at cse.unsw.edu.au (Donald Bruce Stewart) Date: Thu Jan 25 19:47:34 2007 Subject: [Haskell] Views in Haskell In-Reply-To: References: Message-ID: <20070126005216.GA6772@cse.unsw.EDU.AU> Rene_de_Visser: > In my opinion, views are going to make more Haskell more complicated, and > from what I have seen so far, for little gain. We need some kind of pattern extension *now* for bytestring matching/views and bit parsing, though. Stuff that's used in large, real world Haskell programs :) -- Don From simonpj at microsoft.com Fri Jan 26 03:48:42 2007 From: simonpj at microsoft.com (Simon Peyton-Jones) Date: Fri Jan 26 03:43:57 2007 Subject: [Haskell] Views in Haskell In-Reply-To: <20070126005216.GA6772@cse.unsw.EDU.AU> References: <20070126005216.GA6772@cse.unsw.EDU.AU> Message-ID: | > In my opinion, views are going to make more Haskell more complicated, and | > from what I have seen so far, for little gain. | | We need some kind of pattern extension *now* for bytestring | matching/views and bit parsing, though. Stuff that's used in large, real | world Haskell programs :) Would you care to elaborate? After all, pattern guards get quite a lot of the way. Simon From Malcolm.Wallace at cs.york.ac.uk Fri Jan 26 07:19:54 2007 From: Malcolm.Wallace at cs.york.ac.uk (Malcolm Wallace) Date: Fri Jan 26 07:15:55 2007 Subject: help from the community? In-Reply-To: <1169764741.5904.138.camel@localhost.localdomain> References: <5ab17e790701211425j347203b7td898e434d8bb767b@mail.gmail.com> <1169764741.5904.138.camel@localhost.localdomain> Message-ID: <20070126121954.6677f343.Malcolm.Wallace@cs.york.ac.uk> isaac jones wrote: > > http://hackage.haskell.org/trac/haskell-prime/ticket/57 > > Does anyone have any feedback on this work? Yes, here are my thoughts. > PROPOSAL: adopt GHC's convention and treat 'forall' specially in types > but allow it to be used in value declarations. Agree. > [ scheme = 'forall' tvars '.' opt_ctxt type ] > The non-terminal 'tvars' is a sequence of type variables that are > separated by blank spaces. We have a choice if we should allow empty > quantifier sequences. > PROPOSAL: be liberal: > * allow empty quantifier lists > * allow variables that are not mentioned in the body of a type (but warn) > * allow predicates that do not mention quantified variables (but warn?) I cannot see how an empty list of tyvars is useful or desirable in practice: data Foo = Foo (forall . Int) is equivalent to just data Foo = Foo Int so why bother to permit the former? It probably indicates some error in the thinking of the programmer, so the compiler should bring it to her attention. On the other hand, I can imagine a use for phantom type variables in the quantifier (especially if they occur in multi-parameter predicates, but not in the type). So I think accepting them with a warning is reasonable. I can also imagine predicates that do not mention locally-quantified variables - the assumption must be that they mention variables bound on the LHS of the datatype decl instead? e.g. the Show predicate here: data Foo a b = Foo a b | Bar (forall c . (Show b, Relation b c) => (b,c)) Hmm, maybe a simpler version of this example would illustrate what you mean by the proposal (first of the three bullets) to allow an empty quantifier list: data Foo a b = Foo a b | Bar (forall . Show b => b) In which case, does this even count as a polymorphic component at all? Is it not rather GADT-like instead? data Foo a b where Foo :: a -> b -> Foo a b Bar :: Show b => b -> Foo a b > Strict Fields: Where should we place the '!'? > PROPOSAL: before a schema and the schema has to be in parens. Seems the only reasonable choice. > Labelled Fields. > PROPOSAL: Use syntactic equivalence modulo > * alpha renaming > * order/repetition of predicates (i.e. compare predicates as sets) Seems OK. Using entailment looks like it would permit a far more obfuscated programming style, without adding any useful functionality. > Constructor that have polymorphic components cannot appear in the > program without values for their polymorphic fields. I didn't fully understand this requirement. If Haskell-prime gets rank-2 or rank-n types, then do we need to restrict constructors in this way? > We do not allow nested patterns on fields that have polymorphic types. Yes, agree. Regards, Malcolm From iavor.diatchki at gmail.com Fri Jan 26 19:26:05 2007 From: iavor.diatchki at gmail.com (Iavor Diatchki) Date: Fri Jan 26 19:21:17 2007 Subject: help from the community? In-Reply-To: <20070126121954.6677f343.Malcolm.Wallace@cs.york.ac.uk> References: <5ab17e790701211425j347203b7td898e434d8bb767b@mail.gmail.com> <1169764741.5904.138.camel@localhost.localdomain> <20070126121954.6677f343.Malcolm.Wallace@cs.york.ac.uk> Message-ID: <5ab17e790701261626p39208ab9ncc25a6e08566b887@mail.gmail.com> Hello, On 1/26/07, Malcolm Wallace wrote: > > [ scheme = 'forall' tvars '.' opt_ctxt type ] > > The non-terminal 'tvars' is a sequence of type variables that are > > separated by blank spaces. We have a choice if we should allow empty > > quantifier sequences. > > PROPOSAL: be liberal: > > * allow empty quantifier lists > > * allow variables that are not mentioned in the body of a type (but warn) > > * allow predicates that do not mention quantified variables (but warn?) > > I cannot see how an empty list of tyvars is useful or desirable in > practice: > data Foo = Foo (forall . Int) > is equivalent to just > data Foo = Foo Int > so why bother to permit the former? It probably indicates some error in > the thinking of the programmer, so the compiler should bring it to her > attention. > > On the other hand, I can imagine a use for phantom type variables in the > quantifier (especially if they occur in multi-parameter predicates, but > not in the type). So I think accepting them with a warning is > reasonable. > > I can also imagine predicates that do not mention locally-quantified > variables - the assumption must be that they mention variables bound on > the LHS of the datatype decl instead? e.g. the Show predicate here: > > data Foo a b = Foo a b > | Bar (forall c . (Show b, Relation b c) => (b,c)) > > Hmm, maybe a simpler version of this example would illustrate what you > mean by the proposal (first of the three bullets) to allow an empty > quantifier list: > > data Foo a b = Foo a b > | Bar (forall . Show b => b) > > In which case, does this even count as a polymorphic component at all? > Is it not rather GADT-like instead? > > data Foo a b where > Foo :: a -> b -> Foo a b > Bar :: Show b => b -> Foo a b I was thinking that we should allow those special cases because I could not see a reason to disallow them (rather then having a compelling example to use them). You make a good point though, that some of them might indicate an error in the program. So, I guess, the main decision is: do we want to make them illegal (i.e., require an error) or suggest that implementations report a warning? I have no strong feelings either way, but I guess we need to pick something. > > Constructor that have polymorphic components cannot appear in the > > program without values for their polymorphic fields. > > I didn't fully understand this requirement. If Haskell-prime gets > rank-2 or rank-n types, then do we need to restrict constructors in this > way? The issue is the same as for rank-2 types. My suggestion is based on the design adopted by Hugs. The basic idea is that by requiring that functions with rank-2 types (in particular, constructors that have polymorphic fields) are applied to all their polymorphic arguments, we ensure that expressions can be typed by simple types as in HM (and not type schemes). On the pragmatic side this has the benefit that the rank-2 type extension is quite easy to add to a Haskell'98 implementation: the arguments to rank-2 functions are checked pretty much in the same way as expressions with explicit type signatures. The only difference is that the type signature may contain free type variables which doesn't happen in Haskell 98. On the theoretical side we have the benefit that this fairly conservative extension to the type system (we are still working essentially in HM) gives us a big increase in expressiveness (e.g., we can encode System F programs in Haskell). The reason that the type system extension is quite simple is that Haskell 98 compares types for equality by name (as opposed to examining their structure). Other alternatives are systems like MLF (by Didier Le Botlan and Didier R?my) and the relaxed system implemented by GHC. I think that they are both quite interesting but I must admit that for the purposes of Haskell' I am partial to the simplicity of Hug's design. The reason is that I feel that I can explain it to an ordinary Haskell programmer without too much difficulty and it has been sufficient for the situations when I've used rank-2 types. I could be unfairly biased, however, which is why discussions are most welcome! :-) -Iavor From claus.reinke at talk21.com Fri Jan 26 21:22:36 2007 From: claus.reinke at talk21.com (Claus Reinke) Date: Fri Jan 26 21:17:50 2007 Subject: [Haskell] Views in Haskell References: <019301c7408e$d4d71e70$513e7ad5@cr3lt> <86910C0C-B6C4-4268-9B8E-97B775491B27@galois.com> Message-ID: <001701c741ba$03d239e0$f7588351@cr3lt> > 2) There are other reasons why I want to use Haskell-98 and would > like to be able to use other compilers. Thus, I'd want a pattern-binder > preprocessor (extending GHC is not as important to me). I see. though I'd hope that as long as we keep our extensions simple and general enough, the other implementations will pick them up anyway. > Here's my motivating example. Here's a fragment for an STG > interpreter in Haskell-98: > {{{ > rule_CASE_ELIM (Case p alts, s, h, o) = > do > ConApp c as <- ptsTo p h > let matchAlt (Alt c' vs e) | c == c' = Just (vs,e) > matchAlt _ = Nothing > (vs,e) <- matchFirst matchAlt alts > return (e `sub` (vs,as), s, h, o) > }}} yes, abstract machines have inspired many a pattern match extension!-) are we in Maybe, or in anything more complex? view patterns don't seem to apply, but pattern guards do, and lambda-match helps with the local function pattern (ignoring the Match type tag for the moment; given the revival of interest in pattern functions, eg., in view patterns, I ought to try and see whether I can get rid of the type tag in my library for the special case of Maybe): {{{ rule_CASE_ELIM = (| (Case p alts, s, h, o) | ConApp c as <- ptsTo p h , (vs,e) <- matchFirst (| (Alt c' vs e) | c == c' ->(vs,e) ) alts -> (e `sub` (vs,as), s, h, o) ) }}} which isn't quite as abstract as the pattern binder/combinator version, but at least I can see the scoping, which I am at a loss with in the pattern binder version: > I'd like it to have a textual form just a little more abstract, I can > do that with pattern binders and some appropriate combinators: > > {{{ > rule_CASE_ELIM = > { (Case p alts , s, h, o) } > &&& ptsTo p h === { ConApp c as } > &&& alts === matchFirst { Alt #c vs e } > .-> > (e `sub` (vs,as), s, h, o) > }}} > > I'll leave it as an exercise to figure out how the last is > parenthesized ;-). ok, I give up. there seem to be some new combinators, and the pattern binder variables are no longer distinguishable (via $). but unless you've changed the translation as well, the only way the scopes are going to come out right is if the layout is a lie, right? and how does the translation apply to pattern binders not in an infix application, in particular, how do vs/e get to the rhs of .->? Claus From trevion at gmail.com Sat Jan 27 00:04:54 2007 From: trevion at gmail.com (J. Garrett Morris) Date: Sat Jan 27 00:00:05 2007 Subject: Views in Haskell In-Reply-To: <20070125012230.GJ8540@momenergy.repetae.net> References: <20070125012230.GJ8540@momenergy.repetae.net> Message-ID: <6cf91caa0701262104v3dfa04ddt188e626e5dc031fa@mail.gmail.com> On 1/24/07, John Meacham wrote: > I am having a hard time figuring out what views gain you, if anything. > > If you know from the start you want abstract deconstructors, then you > can do that now and it has never been an issue, just mechanical and > verbose: > > > date Term = Ap Term Term | Let Id Term Term > > > > fromAp :: Term -> Maybe (Term,Term) > > fromAp (Ap a b) = Just (a,b) > > fromAp _ = Nothing > > > > > > foo t | Just (a,b) <- fromAp t = ... > > now views give you some (perhaps) nicer syntax for matching these sort > of functions, but they don't make declaring them any less mechanical and > verbose, but more importantly, you still have to know a priori whether > you will need abstract deconstructors or not. I agree completely, although with the caveat that this applies more to Peyton-Jones's view patterns than Wadler's original views, at least as I understood them. I had thought the advantages to views (and the reason I've always been hoping they would eventually be implemented) were: 1) Provide type-class like behavior for type constructors, and 2) Reuse Haskell's existing extremely nice syntax for construction and nested pattern matching. This proposal seems to do neither, and I think the troubles it gets into as soon as you want to match multiple values (extension 1, the Just2 type, etc) demonstrate a somewhat limited applicability. I personally like pattern guards a great deal, as light-weight extensions go, but I'm not sure what view patterns would add over and above them. /g -- It is myself I have never met, whose face is pasted on the underside of my mind. From claus.reinke at talk21.com Sat Jan 27 08:48:59 2007 From: claus.reinke at talk21.com (Claus Reinke) Date: Sat Jan 27 08:44:15 2007 Subject: [Haskell] Views in Haskell References: <008301c73f00$28887590$12528351@cr3lt> <017b01c74005$b7aef860$f3577ad5@cr3lt> Message-ID: <002e01c74219$e6b0cab0$417d7ad5@cr3lt> >> the alternative I'm aiming for, as exhibited in the consP example, would be >> to build patterns systematically from view patterns used as abstract >> de-constructors, composed in the same way as one would compose the >> abstract constructors to build the abstract data structure. > > This would cause an awful lot of kludging to get around the fact you need > to declare a new ADT to declare new abstract deconstructors, and requires > an additional extension for abstract deconstructors to be typeclass > methods - something abstract constructors can do for free. Neither seems > gainful to me. I don't understand? you can define deconstructors for concrete types as well, as many as you like; it is just that when the representation is not hidden in an ADT, noone hinders me from bypassing your deconstructors and go for the concrete representation instead of the abstract representation. and how did additional extensions or typeclasses get into the picture?? perhaps a concrete example will help. as I used the lists-as-arrays example for lambda-match, here it is again for view patterns (implementation not repeated, List made abstract, untested..): module ListArray(List(),nilA,nullA , nilAP ,consA,headA,tailA , consAP ,snocA,initA,tailA , snocAP ) where ..imports.. -- our own array list variant data List a = List (Array Int a) -- constructors, tests, selectors; cons and snoc view nilA :: List a nullA :: List a -> Bool consA :: a -> List a -> List a headA :: List a -> a tailA :: List a -> List a snocA :: List a -> a -> List a lastA :: List a -> a initA :: List a -> List a -- we also define our own pattern constructors nilAP = guard . nullA consAP l = do { guard $ not (nullA l); return ( headA l, tailA l ) } snocAP l = do { guard $ not (nullA l); return ( initA l, lastA l ) } module Examples where import ListArray anA = consA 1 $ consA 2 $ consA 3 $ consA 4 nilA mapA f (nilAP -> ()) = nilA mapA f (consAP -> (h,t)) = consA (f h) (mapA f t) foldA f n (nilAP -> ()) = n foldA f n (consAP -> (h,t)) = f h (foldA f n t) foldA' f n (nilAP -> ()) = n foldA' f n (snocAP -> (i,l)) = f (foldA' f n i) l palindrome (nilAP -> ()) = True palindrome (consAP -> (_, nilAP -> () ) = True palindrome (consAP -> (h, snocAP -> (m,l))) = (h==l) && palindrome m no need for typeclasses so far. we use abstract data and pattern constructors for adts, just as we use concrete data and pattern constructors for concrete types. we choose what view to take of our data simply by choosing what pattern constructors we use (no need for type-based overloaded in/out). and since our pattern constructors are simply functions, we get pattern synonyms as well. we could, I guess, try to package data and pattern constructors together, either by typeclasses: class Cons t where cons :: t instance Cons (a->List a->List a) where cons = ListArray.cons instance Cons (List a->(a,List a)) where cons = ListArray.consP or by declaring consP as the deconstructor corresponding to the cons constructor, as Mark suggested: cons :: a -> List a -> List a cons# :: List a -> (a,List a) both versions could then be used to select the pattern or data constructor, depending on whether cons was used in a pattern or expression context. but neither of these seems strictly necessary to get the benefit of views. if view patterns turn out to be practical, one could then go on to redefine the meaning of data type declarations as implicitly introducing both data and pattern constructors, so f (C x (C y N) = C y (C x N) might one day stand for f (cP -> (x, cP -> (y, nP))) = c y (c x n) but it seems a bit early to discuss such far-reaching changes when we haven't got any experience with view patterns yet. in the mean-time, one might want to extend the refactoring from concrete to abstract types (HaRe has such a refactoring), so that it uses view patterns instead of eliminating pattern matching. since others have raised similar concerns about needing type-classes, I seem to be missing something. could someone please explain what? Claus From loeh at iai.uni-bonn.de Mon Jan 29 04:08:59 2007 From: loeh at iai.uni-bonn.de (Andres Loeh) Date: Mon Jan 29 04:05:49 2007 Subject: help from the community? In-Reply-To: <5ab17e790701261626p39208ab9ncc25a6e08566b887@mail.gmail.com> References: <5ab17e790701211425j347203b7td898e434d8bb767b@mail.gmail.com> <1169764741.5904.138.camel@localhost.localdomain> <20070126121954.6677f343.Malcolm.Wallace@cs.york.ac.uk> <5ab17e790701261626p39208ab9ncc25a6e08566b887@mail.gmail.com> Message-ID: <20070129090859.GX13163@iai.uni-bonn.de> > >I cannot see how an empty list of tyvars is useful or desirable in > >practice: > > data Foo = Foo (forall . Int) > >is equivalent to just > > data Foo = Foo Int > >so why bother to permit the former? It probably indicates some error in > >the thinking of the programmer, so the compiler should bring it to her > >attention. The only reasons that I could see in favor of allowing empty "forall"s is that it might be easier to automatically generate code. Haskell seems to be a bit inconsistent in how it treats empty constructs. For example, empty let and empty where seems to be allowed, but not an empty case? > >On the other hand, I can imagine a use for phantom type variables in the > >quantifier (especially if they occur in multi-parameter predicates, but > >not in the type). So I think accepting them with a warning is > >reasonable. > > > >I can also imagine predicates that do not mention locally-quantified > >variables - the assumption must be that they mention variables bound on > >the LHS of the datatype decl instead? e.g. the Show predicate here: > > > > data Foo a b = Foo a b > > | Bar (forall c . (Show b, Relation b c) => (b,c)) > > > >Hmm, maybe a simpler version of this example would illustrate what you > >mean by the proposal (first of the three bullets) to allow an empty > >quantifier list: > > > > data Foo a b = Foo a b > > | Bar (forall . Show b => b) > > > >In which case, does this even count as a polymorphic component at all? > >Is it not rather GADT-like instead? > > > > data Foo a b where > > Foo :: a -> b -> Foo a b > > Bar :: Show b => b -> Foo a b Would these two have the same meaning? I have a feeling what the GADT is, but no idea what the former type means. > >> Constructor that have polymorphic components cannot appear in the > >> program without values for their polymorphic fields. > > > >I didn't fully understand this requirement. If Haskell-prime gets > >rank-2 or rank-n types, then do we need to restrict constructors in this > >way? Ok, this really boils down to the question of whether we do rank-2 or rank-n types. I'm biased, because I actually use rank-n types frequently, and feel somewhat limited by the rank-2 restrictions. I don't know how many people actually do, though. I can understand Iavor's points that rank-2 might be easier to explain, but at least GHC's rank-n extension has a very detailed paper explaining it, so I guess it's one of the better documented extensions. I very much agree that "nested" patterns for polymorphic components should be disallowed. Cheers, Andres From brianh at metamilk.com Mon Jan 29 04:45:54 2007 From: brianh at metamilk.com (Brian Hulley) Date: Mon Jan 29 04:39:53 2007 Subject: [Haskell] Views in Haskell References: <008301c73f00$28887590$12528351@cr3lt><017b01c74005$b7aef860$f3577ad5@cr3lt> <002e01c74219$e6b0cab0$417d7ad5@cr3lt> Message-ID: <003e01c7438a$49f50250$6ae52950@osmet> Claus Reinke wrote: > > mapA f (nilAP -> ()) = nilA > mapA f (consAP -> (h,t)) = consA (f h) (mapA f t) > > foldA f n (nilAP -> ()) = n > foldA f n (consAP -> (h,t)) = f h (foldA f n t) To me this exactly illustrates why view patterns are a bad idea: you've taken some concrete type, abstracted it to replace the actual structure by a list structure, then defined map and fold over the list structure. This means that map and fold can't take advantage of the actual concrete structure and are therefore condemned to use the inefficient linear structure imposed by the list abstraction. For example implementing map over a tree directly, gives the possibility of parallel execution since different subtrees can be mapped independently. But when you view the tree abstractly as a list, no such parallel execution can take place. Therefore surely it is better that map and fold are defined for each ADT separately, with the separate definitions hidden behind a type class, than to attempt to define them "outside" the definition of the ADT using view patterns? Brian. -- http://www.metamilk.com From claus.reinke at talk21.com Mon Jan 29 07:15:26 2007 From: claus.reinke at talk21.com (Claus Reinke) Date: Mon Jan 29 07:10:32 2007 Subject: [Haskell] Views in Haskell References: <008301c73f00$28887590$12528351@cr3lt><017b01c74005$b7aef860$f3577ad5@cr3lt> <002e01c74219$e6b0cab0$417d7ad5@cr3lt> <003e01c7438a$49f50250$6ae52950@osmet> Message-ID: <000301c7439f$29fb8900$8f458351@cr3lt> >> mapA f (nilAP -> ()) = nilA >> mapA f (consAP -> (h,t)) = consA (f h) (mapA f t) >> >> foldA f n (nilAP -> ()) = n >> foldA f n (consAP -> (h,t)) = f h (foldA f n t) yes, maps and folds are likely to be parts of the ADT interface, rather than defined on top of it. I just used them as simple and familiar examples, so that we have something to compare them with. > To me this exactly illustrates why view patterns are a bad idea: whether or not an ADT interface is well designed, according to some metric, does not tell us whether or not the language features used in the code are good or not. hiding the internal representation always raises questions of whether the exposed interface is still expressive enough or allows efficient code to be written, even without view patterns. in other words, ADTs do not only conflict with the ease of pattern matching, but also with other possible advantages of using the internal representation directly. view patterns help to address the convenience/readability issue, but the other issues remain to be addressed by careful interface design. in this particular case, I believe that separate compilation is the main concern standing in the way of optimizing the abstract view away. Claus > you've taken some concrete type, abstracted it to replace the actual structure > by a list structure, then defined map and fold over the list structure. This > means that map and fold can't take advantage of the actual concrete > structure and are therefore condemned to use the inefficient linear > structure imposed by the list abstraction. > > For example implementing map over a tree directly, gives the possibility of > parallel execution since different subtrees can be mapped independently. But > when you view the tree abstractly as a list, no such parallel execution can > take place. Therefore surely it is better that map and fold are defined for > each ADT separately, with the separate definitions hidden behind a type > class, than to attempt to define them "outside" the definition of the ADT > using view patterns? > > Brian. > -- > http://www.metamilk.com From simonpj at microsoft.com Tue Jan 30 11:27:18 2007 From: simonpj at microsoft.com (Simon Peyton-Jones) Date: Tue Jan 30 11:21:59 2007 Subject: help from the community? In-Reply-To: <5ab17e790701261626p39208ab9ncc25a6e08566b887@mail.gmail.com> References: <5ab17e790701211425j347203b7td898e434d8bb767b@mail.gmail.com> <1169764741.5904.138.camel@localhost.localdomain> <20070126121954.6677f343.Malcolm.Wallace@cs.york.ac.uk> <5ab17e790701261626p39208ab9ncc25a6e08566b887@mail.gmail.com> Message-ID: | > I can also imagine predicates that do not mention locally-quantified | > variables - the assumption must be that they mention variables bound on | > the LHS of the datatype decl instead? e.g. the Show predicate here: | > | > data Foo a b = Foo a b | > | Bar (forall c . (Show b, Relation b c) => (b,c)) | > | > Hmm, maybe a simpler version of this example would illustrate what you | > mean by the proposal (first of the three bullets) to allow an empty | > quantifier list: | > | > data Foo a b = Foo a b | > | Bar (forall . Show b => b) | > | > In which case, does this even count as a polymorphic component at all? | > Is it not rather GADT-like instead? | > | > data Foo a b where | > Foo :: a -> b -> Foo a b | > Bar :: Show b => b -> Foo a b | | I was thinking that we should allow those special cases because I | could not see a reason to disallow them (rather then having a | compelling example to use them). You make a good point though, that | some of them might indicate an error in the program. So, I guess, the | main decision is: do we want to make them illegal (i.e., require an | error) or suggest that implementations report a warning? I have no | strong feelings either way, but I guess we need to pick something. I think I know what we should do on this particular point. I've even documented it here: http://www.haskell.org/ghc/dist/current/docs/users_guide/data-type-extensions.html#gadt-style I would like to urge this design, or one close to it, for Haskell'. Note that this is *not* the same as adopting GADTs. Simon From benjamin.franksen at bessy.de Tue Jan 30 16:23:03 2007 From: benjamin.franksen at bessy.de (Benjamin Franksen) Date: Tue Jan 30 16:18:25 2007 Subject: help from the community? References: <5ab17e790701211425j347203b7td898e434d8bb767b@mail.gmail.com> <1169764741.5904.138.camel@localhost.localdomain> <20070126121954.6677f343.Malcolm.Wallace@cs.york.ac.uk> <5ab17e790701261626p39208ab9ncc25a6e08566b887@mail.gmail.com> <20070129090859.GX13163@iai.uni-bonn.de> Message-ID: Andres Loeh wrote: >> >I cannot see how an empty list of tyvars is useful or desirable in >> >practice: >> > data Foo = Foo (forall . Int) >> >is equivalent to just >> > data Foo = Foo Int >> >so why bother to permit the former? It probably indicates some error in >> >the thinking of the programmer, so the compiler should bring it to her >> >attention. > > The only reasons that I could see in favor of allowing empty "forall"s > is that it might be easier to automatically generate code. Haskell > seems to be a bit inconsistent in how it treats empty constructs. For > example, empty let and empty where seems to be allowed, but not an > empty case? Just a little remark on the side: 'If' and 'case' demand exactly one expression. In such cases allowing zero expressions is not a generalization but an unnecessary complication. 'Let' and 'where' allow any number of bindings, so allowing zero bindings (instead of demanding at least one) is a simplification. Upshot: everywhere the syntax allows a 'list' of things, one should consider allowing the empty list, too. Cheers Ben From loeh at iai.uni-bonn.de Tue Jan 30 17:09:50 2007 From: loeh at iai.uni-bonn.de (Andres Loeh) Date: Tue Jan 30 16:56:52 2007 Subject: help from the community? In-Reply-To: References: <5ab17e790701211425j347203b7td898e434d8bb767b@mail.gmail.com> <1169764741.5904.138.camel@localhost.localdomain> <20070126121954.6677f343.Malcolm.Wallace@cs.york.ac.uk> <5ab17e790701261626p39208ab9ncc25a6e08566b887@mail.gmail.com> <20070129090859.GX13163@iai.uni-bonn.de> Message-ID: <20070130220950.GJ13163@iai.uni-bonn.de> > > The only reasons that I could see in favor of allowing empty "forall"s > > is that it might be easier to automatically generate code. Haskell > > seems to be a bit inconsistent in how it treats empty constructs. For > > example, empty let and empty where seems to be allowed, but not an > > empty case? > > Just a little remark on the side: 'If' and 'case' demand exactly one > expression. In such cases allowing zero expressions is not a generalization > but an unnecessary complication. 'Let' and 'where' allow any number of > bindings, so allowing zero bindings (instead of demanding at least one) is > a simplification. I meant the branches of a case (the report specifies at least 1). Similarly, the report specifies that lambdas must have at least one argument, infix declarations must not be empty and datatype declarations must not be empty (the latter will definitely be fixed). Cheers, Andres From tullsen at galois.com Tue Jan 30 21:16:20 2007 From: tullsen at galois.com (Mark Tullsen) Date: Tue Jan 30 21:11:37 2007 Subject: [Haskell] Views in Haskell In-Reply-To: <001701c741ba$03d239e0$f7588351@cr3lt> References: <019301c7408e$d4d71e70$513e7ad5@cr3lt> <86910C0C-B6C4-4268-9B8E-97B775491B27@galois.com> <001701c741ba$03d239e0$f7588351@cr3lt> Message-ID: On Jan 26, 2007, at 6:22 PM, Claus Reinke wrote: >> 2) There are other reasons why I want to use Haskell-98 and >> would like to be able to use other compilers. Thus, I'd want a >> pattern-binder preprocessor (extending GHC is not as important to >> me). > > I see. though I'd hope that as long as we keep our extensions > simple and > general enough, the other implementations will pick them up anyway. > >> Here's my motivating example. Here's a fragment for an STG >> interpreter in Haskell-98: >> {{{ >> rule_CASE_ELIM (Case p alts, s, h, o) = >> do >> ConApp c as <- ptsTo p h >> let matchAlt (Alt c' vs e) | c == c' = Just (vs,e) >> matchAlt _ = Nothing >> (vs,e) <- matchFirst matchAlt alts >> return (e `sub` (vs,as), s, h, o) >> }}} > > yes, abstract machines have inspired many a pattern match extension!-) > > are we in Maybe, or in anything more complex? Yep, just Maybe. > view patterns don't seem to apply, but pattern guards do, and > lambda-match helps with the local function pattern (ignoring the > Match type tag for the moment; given the revival of interest in > pattern functions, eg., in view patterns, I ought to try and see > whether I can get rid of the type tag in my library for the special > case of Maybe): > > {{{ > rule_CASE_ELIM = > (| (Case p alts, s, h, o) | ConApp c as <- ptsTo p h > , (vs,e) <- matchFirst (| (Alt c' vs e) | c == c' ->(vs,e) ) > alts > -> (e `sub` (vs,as), s, h, o) ) > }}} > > which isn't quite as abstract as the pattern binder/combinator > version, > but at least I can see the scoping, Thanks for showing how it looks with lambda-match, I see that lambda- matches use more than patterns, they use guards too. > which I am at a loss with in the pattern > binder version: > >> I'd like it to have a textual form just a little more abstract, I >> can do that with pattern binders and some appropriate combinators: >> {{{ >> rule_CASE_ELIM = >> { (Case p alts , s, h, o) } >> &&& ptsTo p h === { ConApp c as } >> &&& alts === matchFirst { Alt #c vs e } >> .-> >> (e `sub` (vs,as), s, h, o) >> }}} >> I'll leave it as an exercise to figure out how the last is >> parenthesized ;-). > > ok, I give up. there seem to be some new combinators, yes, but nothing fancy: (&&&) :: (a -> Maybe b) -> (b -> Maybe c) -> a -> Maybe c (&&&) = (.:) -- as in the paper (===) :: a -> (a -> Maybe b) -> Maybe b (===) a p = p a > and the pattern binder variables are no longer distinguishable (via > $). In this example I'm dropping the $: it's less clear what's going on but it looks cleaner, more like Haskell patterns. > but unless you've changed the translation as well, the only way the > scopes are going to come out right is if the layout is a lie, right? The layout /is/ a lie :-( but the scope rule is pretty simple: in this expression {p} `op` e everything bound in p scopes over all e. So, all the variables in the {p}'s above scope to the end of the RHS expression. > and how does the translation apply to pattern binders not in an > infix application, in particular, how do vs/e get to > the rhs of .->? > > Claus All the pattern binders here /are/ in an infix application, here's the parenthesized version: {{{ rule_CASE_ELIM = { (Case p alts , s, h, o) } &&& (ptsTo p h ==> { ConApp c as } &&& (alts === (matchFirst ({ Alt #c vs e } .-> (e `sub` (vs,as), s, h, o))))) }}} (Oops, I see I'm using # where in the paper I used "=".) I also fixed a type error (nothing like ghci to fix some design problems), I'm now using an additional (rather simple) combinator: (==>) :: Maybe a -> (a -> Maybe b) -> Maybe b (==>) = (>>=) - Mark From brianh at metamilk.com Tue Jan 30 23:14:41 2007 From: brianh at metamilk.com (Brian Hulley) Date: Tue Jan 30 23:09:09 2007 Subject: help from the community? References: <5ab17e790701211425j347203b7td898e434d8bb767b@mail.gmail.com><1169764741.5904.138.camel@localhost.localdomain><20070126121954.6677f343.Malcolm.Wallace@cs.york.ac.uk><5ab17e790701261626p39208ab9ncc25a6e08566b887@mail.gmail.com><20070129090859.GX13163@iai.uni-bonn.de> <20070130220950.GJ13163@iai.uni-bonn.de> Message-ID: <002501c744ee$55c3d0b0$ebea2950@osmet> Andres Loeh wrote: >>> The only reasons that I could see in favor of allowing empty >>> "forall"s is that it might be easier to automatically generate >>> code. Haskell seems to be a bit inconsistent in how it treats empty >>> constructs. For example, empty let and empty where seems to be >>> allowed, but not an empty case? >> >> Just a little remark on the side: 'If' and 'case' demand exactly one >> expression. In such cases allowing zero expressions is not a >> generalization but an unnecessary complication. 'Let' and 'where' >> allow any number of bindings, so allowing zero bindings (instead of >> demanding at least one) is a simplification. > > I meant the branches of a case (the report specifies at least 1). I think it's important to keep some possibility for the compiler to detect probable errors as syntax errors. If all syntax is inhabited by strange defaults then this just means simple errors will go undetected eg: let a = case foo of Here, the user has probably got sidetracked into editing some other part of the program and just forgotten to get back to fill in the cases for the case construct. Allowing zero cases means the user will get a strange runtime error instead as the "function" part of the case is undefined. let z = \y (foo y) Here, it seems clear that the user has just forgotten to type the -> which means a simple syntax error would get transformed into a much more puzzling (esp for a newbie) type error. The difference between the above and 'let' and 'where' is that if the enclosing construct (eg a binding) is complete, we know that the contents of the 'let' are complete (since extra local bindings added afterwards would be irrelevant) similarly for 'where', and if the enclosing construct is not complete the compiler will detect this. Therefore I think the original choices are the best since they don't seem inconsistent when looked at this way. Brian. -- http://www.metamilk.com From loeh at iai.uni-bonn.de Wed Jan 31 05:49:15 2007 From: loeh at iai.uni-bonn.de (Andres Loeh) Date: Wed Jan 31 05:36:17 2007 Subject: help from the community? In-Reply-To: <002501c744ee$55c3d0b0$ebea2950@osmet> References: <20070130220950.GJ13163@iai.uni-bonn.de> <002501c744ee$55c3d0b0$ebea2950@osmet> Message-ID: <20070131104915.GK13163@iai.uni-bonn.de> > >>Just a little remark on the side: 'If' and 'case' demand exactly one > >>expression. In such cases allowing zero expressions is not a > >>generalization but an unnecessary complication. 'Let' and 'where' > >>allow any number of bindings, so allowing zero bindings (instead of > >>demanding at least one) is a simplification. > > > >I meant the branches of a case (the report specifies at least 1). > > I think it's important to keep some possibility for the compiler to detect > probable errors as syntax errors. If all syntax is inhabited by strange > defaults then this just means simple errors will go undetected eg: > > let a = case foo of > > Here, the user has probably got sidetracked into editing some other part of > the program and just forgotten to get back to fill in the cases for the > case construct. Allowing zero cases means the user will get a strange > runtime error instead as the "function" part of the case is undefined. I agree. On the other hand, if there are uninhabited types (modulo _|_), it might be nice to have an empty case as an explicit eliminator. > let z = \y (foo y) > > Here, it seems clear that the user has just forgotten to type the -> which > means a simple syntax error would get transformed into a much more puzzling > (esp for a newbie) type error. Again, for the lambda I obviously meant the case of 0 variables, i.e. something like (\ -> y) which would then just be equivalent to y. I think this case is probably the one that's most comparable to the situation in question (whether to allow empty forall's). Since the designers of previous Haskell versions obviously thought it's a good idea to disallow empty lambdas, let's disallow empty forall's as well. Cheers, Andres From ctm at cs.nott.ac.uk Wed Jan 31 06:28:40 2007 From: ctm at cs.nott.ac.uk (Conor McBride) Date: Wed Jan 31 06:23:43 2007 Subject: help from the community? In-Reply-To: <20070131104915.GK13163@iai.uni-bonn.de> References: <20070130220950.GJ13163@iai.uni-bonn.de> <002501c744ee$55c3d0b0$ebea2950@osmet> <20070131104915.GK13163@iai.uni-bonn.de> Message-ID: <45C07D68.60306@cs.nott.ac.uk> Hi Andres Loeh wrote: >> I think it's important to keep some possibility for the compiler to detect >> probable errors as syntax errors. If all syntax is inhabited by strange >> defaults then this just means simple errors will go undetected eg: >> >> let a = case foo of >> >> Here, the user has probably got sidetracked into editing some other part of >> the program and just forgotten to get back to fill in the cases for the >> case construct. Allowing zero cases means the user will get a strange >> runtime error instead as the "function" part of the case is undefined. >> > > I agree. On the other hand, if there are uninhabited types (modulo _|_), it > might be nice to have an empty case as an explicit eliminator. > Even if GADTs aren't on the immediate agenda, it's still important to design with them in mind. Empty case analyses are far from odd in that setting. They certainly show up all the time in Epigram programming, and it's important to show them as part of the explanation that a program covers all cases. Whether totality is being enforced or not, it's good to be clear that a piece of code is missing because it isn't needed, not because it's been forgotten or left as an "undefined" stub. However, it might be worth having a separate notation or keyword, unmistakably for the purpose of refuting bogus elements of empty datatypes: "refute foo" or "nocase foo" or "foo stinks". Moreover, we could consider having a compiler warning if the programmer seeks to refute an element of a datatype which can contain a constructor pattern. So, as far as Haskell' is concerned, I'd favour forbidding non-empty cases, but only because I favour having some more explicit syntax for empty cases, further down the line. All the best Conor From bulat.ziganshin at gmail.com Wed Jan 31 09:44:29 2007 From: bulat.ziganshin at gmail.com (Bulat Ziganshin) Date: Wed Jan 31 09:49:12 2007 Subject: [Haskell] Views in Haskell In-Reply-To: References: Message-ID: <1086178323.20070131174429@gmail.com> Hello Rene, Wednesday, January 24, 2007, 10:49:06 PM, you wrote: > Going by the traffic over the previous months, I think that class aliases or > extensible records would be higher on most peoples lists than views. i think that proper views is a must for Haskell - "We are keen on abstraction, but pattern matching is so convenient that we break abstractions all the time. It's our dirty little secret. " we need views in order to stop dealing with concrete datatypes and start writing polymorphic functions. just imagine that the following definition sum [x] = x sum (x:xs) = x + sum xs may deal with *anything*, from strict list to patricia tree. isn't that great? -- Best regards, Bulat mailto:Bulat.Ziganshin@gmail.com From bulat.ziganshin at gmail.com Wed Jan 31 09:53:08 2007 From: bulat.ziganshin at gmail.com (Bulat Ziganshin) Date: Wed Jan 31 09:49:15 2007 Subject: ADT views Re: [Haskell] Views in Haskell In-Reply-To: References: Message-ID: <1669608254.20070131175308@gmail.com> Hello Simon, Monday, January 22, 2007, 5:57:27 PM, you wrote: > adding "view patterns" to Haskell. many of us was attracted to Haskell because it has clear and simple syntax. but many Hugs/GHC extensions done by independent developers differ in the syntax they used, because these developers either has their own taste or just don't bother with syntax issues. you may remember my examples of how the guards syntax may be reused for GADTs and class declarations: data T a = C1 a | Show a || C2 a | Read a instance Binary a | Storable a where ... but unfortunately we've finished with 3 different syntax for the same things i'm sorry for so big introduction but this shows why i don't like the *syntax* you've proposed. you wrote "The key feature of this proposal is its modesty, rather than its ambition..." that means that this proposal is great for you as implementor - you should write a minimal amount of code to add this to GHC. but let's look at this from viewpoint of one who learn and then use Haskell: first, he should learn two syntax to do matching instead of one. second, he should learn how to implement them both. third, he need to make decision of whether to provide abstract interface to his datatypes or not. if he make a bad decision, he will end either in rewriting lot of code (and change is not s///-style !) or having a lots of trivial definitions like data List a = Nil | Cons a (List a) nil Nil = Just Nil nil _ = Nothing cons (Cons a b) = Just (a,b) cons _ = Nothing then IDEs will automate this code generation and "refactoring" of code, etc, etc :) >On the other hand, view patterns can do arbitrary computation, >perhaps expensive. So it's good to have a syntactically-distinct >notation that reminds the programmer that some computation beyond >ordinary pattern matching may be going on. *you* said :) are you don't know that explicit control of generated code is "advantage" of low-level languages? we use higher-level languages exactly to avoid dealing with implementation details. as far as we can describe algorithm in some form understandable by computer, we are done. lazy evaluation, classes and even plain functions are the tools to describe algorithm without having any guarantees about its efficiency so, i propose to define views in a way that 1) preserves syntax compatibility with existing patterns 2) allow to define "class of views" to provide common interface to all sequences, for example 3) old-good guards may be used instead of Nothing to provide "backtacking" (are you don't think that we already have full Prolog power between "|" and "="? :) something like this: data Coord = Coord Float Float view of Coord = Polar Float Float where Polar r d = Coord (r*d) (r+d) -- construction Coord x y | x/=0 || y/=0 = Polar (x*y) (x+y) -- matching f :: Coord -> Float f (Polar r _) = r f (Coord 0 0) = error "..." class ListLike c e where head :: c -> e tail :: c -> c class view of ListLike where Cons :: e -> e -> c Nil :: c instance ListLike [a] a where head (x:xs) = x tail (x:xs) = xs instance view ListLike [a] a where Cons x xs = x:xs -- for constructing new values using Cons (x:xs) = Cons x xs -- used to match Cons in patterns Nil = xs xs | null xs = Nil i know that this is longer way (and probably will be never implemented) but the language should remain orthogonal. otherwise it will dead in terrible tortures :) -- Best regards, Bulat mailto:Bulat.Ziganshin@gmail.com From droundy at darcs.net Wed Jan 31 11:12:05 2007 From: droundy at darcs.net (David Roundy) Date: Wed Jan 31 11:07:03 2007 Subject: ADT views Re: [Haskell] Views in Haskell In-Reply-To: <1669608254.20070131175308@gmail.com> References: <1669608254.20070131175308@gmail.com> Message-ID: <20070131161202.GB26052@abridgegame.org> On Wed, Jan 31, 2007 at 05:53:08PM +0300, Bulat Ziganshin wrote: > something like this: > > data Coord = Coord Float Float > view of Coord = Polar Float Float where > Polar r d = Coord (r*d) (r+d) -- construction > Coord x y | x/=0 || y/=0 = Polar (x*y) (x+y) -- matching This is somewhat pretty, but in spite of your desire to avoid creating new syntax, you have just done so, and in the process made views more limited. Pattern matching sytax remains the same, but a new declaration syntax has been added. And now in order to pattern match on a function it needs to explicitely be declared as a "view". And unless you are planning to allow one-way views (you don't give any examples of that), "view functions" must be invertible, which greatly weakens their power. If you choose to allow one-way views (non-invertible functions), then I'd vote for not allowing two-way views, as it adds complexity without adding any appreciable gain. I don't like your use of capital letters for ordinary functions, I enjoy having the syntax tell me whether (Foo 1) might or might not be an expensive operation. Finally, you've replaced Simon's explicit incomplete function using Maybe with an implicit incomplete function that returns _|_ when the view doesn't match. I find this rather unappealing. I certainly prefer *intentionally* incomplete functions to return Maybe somthing, rather than just bombing out when given invalid input. I suppose you'll point out that the view Coord is a function that you can never explicitely call, but to me that just makes things even more confusing. Now we're defining functions that we can only use in pattern matching, but can never call. -- David Roundy http://www.darcs.net From bulat.ziganshin at gmail.com Wed Jan 31 13:28:30 2007 From: bulat.ziganshin at gmail.com (Bulat Ziganshin) Date: Wed Jan 31 13:25:10 2007 Subject: ADT views Re: [Haskell] Views in Haskell In-Reply-To: <20070131161202.GB26052@abridgegame.org> References: <1669608254.20070131175308@gmail.com> <20070131161202.GB26052@abridgegame.org> Message-ID: <1548756987.20070131212830@gmail.com> Hello David, Wednesday, January 31, 2007, 7:12:05 PM, you wrote: >> data Coord = Coord Float Float >> view of Coord = Polar Float Float where >> Polar r d = Coord (r*d) (r+d) -- construction >> Coord x y | x/=0 || y/=0 = Polar (x*y) (x+y) -- matching > This is somewhat pretty, but in spite of your desire to avoid creating new > syntax, you have just done so, and in the process made views more limited. > Pattern matching sytax remains the same, but a new declaration syntax has > been added. And now in order to pattern match on a function it needs to > explicitely be declared as a "view". yes. among the possible uses for views i clearly prefers the following: definition of abstract data views that may differ from actual type representation. moreover, i think that this facility should be syntactically indistinguishable from ordinary data constructor patterns in order to simplify learning and using of language. *defining* view is a rare operation, using it - very common so my first point is that views should be used in just the same way as ordinary constructors, both on left and right side: f (Polar r a) = Polar (r*2) a Next, i don't think that ability to use any functions in view buy something important. pattern guards can be used for arbitrary functions, or such function can be used in view definition. view, imho, is not a function - it's a two-way conversion between abstract and real data representation which has one or more alternative variants - just like Algebraic Data Types. so, when defining a view, i want to have ability to define exactly all variants alternative to each other. for another representation, another view should be created. so view Polar Float Float of Coord where constructor (Polar r a) means (Coord (r*sin a) (r*cos a)) match pattern (Polar (sqrt(x*x+y*y)) (atan(y/x))) for (Coord x y) where x/=0 (Polar y (pi/2)) for (Coord x y) where y>0 (Polar (-y) (-pi/2)) for (Coord x y) where y<0 of course, my syntax is cumbersome. that is important is that view definition should be explicit (no arbitrary functions), it should mention all possible alternatives and provide a way to use the same constructor name both for construction of new values and matching existing ones. this all together should allow to transparently use ADT views instead of plain ADTs > And unless you are planning to allow one-way views (you don't give any > examples of that), "view functions" must be invertible, which greatly > weakens their power. If you choose to allow one-way views (non-invertible > functions), then I'd vote for not allowing two-way views, as it adds > complexity without adding any appreciable gain. > I don't like your use of capital letters for ordinary functions, I enjoy > having the syntax tell me whether (Foo 1) might or might not be an > expensive operation. the whole idea of abstraction is to not give users any knowledge aside from algorithmic specifications. when you write (x+y) you don't know whether this (+) will end in ADD instruction or sending expedition to Mars :) why you need low-level control over data matchers exported by library but not over its functions? > Finally, you've replaced Simon's explicit incomplete function using Maybe > with an implicit incomplete function that returns _|_ when the view doesn't > match. it's an independent idea that can be used for Simon's syntax or don't used at all. really, we need Prolog-like backtracking mechanism, i.e. way to say "this pattern don't match input value, please try the next alternative". Simon emulated backtracking with Maybe, one can does the same with return/fail, i figured out one more way - just allow recursive use of function guards. Here, if all alternatives for Polar pattern fails, then the whole Polar pattern don't match and we should try the next alternative. so, the following: f (Polar r a) = Polar (r*2) a f (Coord 0 0) = Coord 0 0 should be translated into: f (Coord x y) | x/=0 = Coord (r*2*sin a) (r*2*cos a) where r = sqrt(x*x+y*y) a = atan(y/x) f (Coord x y) | y>0 = Coord (r*2*sin a) (r*2*cos a) where r = y a = pi/2 f (Coord x y) | y<0 = Coord (r*2*sin a) (r*2*cos a) where r = -y a = -pi/2 f (Coord 0 0) = Coord 0 0 > I find this rather unappealing. I certainly prefer *intentionally* > incomplete functions to return Maybe somthing, rather than just bombing out > when given invalid input. I suppose you'll point out that the view Coord > is a function that you can never explicitely call, but to me that just > makes things even more confusing. Now we're defining functions that we can > only use in pattern matching, but can never call. i hope that now my idea is clear -- Best regards, Bulat mailto:Bulat.Ziganshin@gmail.com From taralx at gmail.com Wed Jan 31 17:11:48 2007 From: taralx at gmail.com (Taral) Date: Wed Jan 31 17:06:42 2007 Subject: help from the community? In-Reply-To: <45C07D68.60306@cs.nott.ac.uk> References: <20070130220950.GJ13163@iai.uni-bonn.de> <002501c744ee$55c3d0b0$ebea2950@osmet> <20070131104915.GK13163@iai.uni-bonn.de> <45C07D68.60306@cs.nott.ac.uk> Message-ID: On 1/31/07, Conor M