caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
* Patterns that evaluate
@ 2007-02-13 22:04 Jacques Carette
  2007-02-13 22:07 ` [Caml-list] " Jon Harrop
  2007-02-14 20:29 ` Nathaniel Gray
  0 siblings, 2 replies; 22+ messages in thread
From: Jacques Carette @ 2007-02-13 22:04 UTC (permalink / raw)
  To: OCaml

I recently wrote some ocaml code which "worked", but not as I 
intended...  The test cases I tried worked, but I should have tested 
harder.  Apparently I was under the mistaken impression that OCaml's 
pattern-matching was more "first class"!  So I wrote (in part):

let buildsimp cast e f1 f2 = fun e1 -> fun e2 -> match (e1,e2) with
                                                 | ({st = Some e}, _) -> e2

and I expected it to work.  Only a code review by a colleague 'found' 
this bug in my code.

Question: would it be a difficult extension?  This seemed so "natural", 
I just "used" the feature before it was quite there yet ;-).

Jacques

PS: I guess I had first-class patterns on the brain; Maple has them 
[under the misleadingly-named function "typematch"] (but that's 
cheating, I know) and W. Kahl's Pattern Matching Calculus allows it, and 
I wrote a joint paper with Wolfram describing a categorical semantics 
for the PMC.


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [Caml-list] Patterns that evaluate
  2007-02-13 22:04 Patterns that evaluate Jacques Carette
@ 2007-02-13 22:07 ` Jon Harrop
  2007-02-14  0:10   ` Jacques Carette
                     ` (2 more replies)
  2007-02-14 20:29 ` Nathaniel Gray
  1 sibling, 3 replies; 22+ messages in thread
From: Jon Harrop @ 2007-02-13 22:07 UTC (permalink / raw)
  To: caml-list

On Tuesday 13 February 2007 22:04, Jacques Carette wrote:
> I recently wrote some ocaml code which "worked", but not as I
> intended...  The test cases I tried worked, but I should have tested
> harder.  Apparently I was under the mistaken impression that OCaml's
> pattern-matching was more "first class"!  So I wrote (in part):
>
> let buildsimp cast e f1 f2 = fun e1 -> fun e2 -> match (e1,e2) with
>
>                                                  | ({st = Some e}, _) -> e2
>
> and I expected it to work.  Only a code review by a colleague 'found'
> this bug in my code.
>
> Question: would it be a difficult extension?  This seemed so "natural",
> I just "used" the feature before it was quite there yet ;-).

F# just introduced active patterns, which does what you want AFAIK. Of course, 
you must disambiguate that from the OCaml's current interpretation of the 
above (binding "e").

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [Caml-list] Patterns that evaluate
  2007-02-13 22:07 ` [Caml-list] " Jon Harrop
@ 2007-02-14  0:10   ` Jacques Carette
  2007-02-14 18:20   ` Edgar Friendly
  2007-02-14 22:34   ` Martin Jambon
  2 siblings, 0 replies; 22+ messages in thread
From: Jacques Carette @ 2007-02-14  0:10 UTC (permalink / raw)
  To: Jon Harrop; +Cc: caml-list

Jon Harrop wrote:
> F# just introduced active patterns, which does what you want AFAIK. Of course, 
> you must disambiguate that from the OCaml's current interpretation of the 
> above (binding "e").
>   
Yes, of course - but I would be more than happy to do that.

Jacques


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [Caml-list] Patterns that evaluate
  2007-02-13 22:07 ` [Caml-list] " Jon Harrop
  2007-02-14  0:10   ` Jacques Carette
@ 2007-02-14 18:20   ` Edgar Friendly
  2007-02-14 18:55     ` Gerd Stolpmann
  2007-02-14 22:34   ` Martin Jambon
  2 siblings, 1 reply; 22+ messages in thread
From: Edgar Friendly @ 2007-02-14 18:20 UTC (permalink / raw)
  To: Jon Harrop; +Cc: caml-list

Jon Harrop wrote:
> On Tuesday 13 February 2007 22:04, Jacques Carette wrote:
>> I recently wrote some ocaml code which "worked", but not as I
>> intended...  The test cases I tried worked, but I should have tested
>> harder.  Apparently I was under the mistaken impression that OCaml's
>> pattern-matching was more "first class"!  So I wrote (in part):
>>
>> let buildsimp cast e f1 f2 = fun e1 -> fun e2 -> match (e1,e2) with
>>
>>                                                  | ({st = Some e}, _) -> e2
>>
>> and I expected it to work.  Only a code review by a colleague 'found'
>> this bug in my code.
>>
>> Question: would it be a difficult extension?  This seemed so "natural",
>> I just "used" the feature before it was quite there yet ;-).
> 
> F# just introduced active patterns, which does what you want AFAIK. Of course, 
> you must disambiguate that from the OCaml's current interpretation of the 
> above (binding "e").
> 
The two options I see are:
1) noting a re-binding, and automatically testing against the value of 
that previous binding
2) extra syntax (maybe || instead of | before active match constructs)

In the first case, there's backwards compatibility issues.  Wouldn't it 
be useful to have the compiler warn on such uses, to make people aware 
of rebindings performed in their code?

E.


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [Caml-list] Patterns that evaluate
  2007-02-14 18:20   ` Edgar Friendly
@ 2007-02-14 18:55     ` Gerd Stolpmann
  2007-02-14 19:10       ` Denis Bueno
                         ` (2 more replies)
  0 siblings, 3 replies; 22+ messages in thread
From: Gerd Stolpmann @ 2007-02-14 18:55 UTC (permalink / raw)
  To: Edgar Friendly; +Cc: Jon Harrop, caml-list

Am Mittwoch, den 14.02.2007, 12:20 -0600 schrieb Edgar Friendly:
> Jon Harrop wrote:
> > On Tuesday 13 February 2007 22:04, Jacques Carette wrote:
> >> I recently wrote some ocaml code which "worked", but not as I
> >> intended...  The test cases I tried worked, but I should have tested
> >> harder.  Apparently I was under the mistaken impression that OCaml's
> >> pattern-matching was more "first class"!  So I wrote (in part):
> >>
> >> let buildsimp cast e f1 f2 = fun e1 -> fun e2 -> match (e1,e2) with
> >>
> >>                                                  | ({st = Some e}, _) -> e2
> >>
> >> and I expected it to work.  Only a code review by a colleague 'found'
> >> this bug in my code.
> >>
> >> Question: would it be a difficult extension?  This seemed so "natural",
> >> I just "used" the feature before it was quite there yet ;-).
> > 
> > F# just introduced active patterns, which does what you want AFAIK. Of course, 
> > you must disambiguate that from the OCaml's current interpretation of the 
> > above (binding "e").
> > 
> The two options I see are:
> 1) noting a re-binding, and automatically testing against the value of 
> that previous binding
> 2) extra syntax (maybe || instead of | before active match constructs)
> 
> In the first case, there's backwards compatibility issues.  Wouldn't it 
> be useful to have the compiler warn on such uses, to make people aware 
> of rebindings performed in their code?

You are a bit quick. Before discussing syntax it is more important to
define the semantics of such patterns. I mean we have already three
predefined kinds of equality in O'Caml:

- ( == )
- ( = )
- (fun x y -> compare x y = 0)

I admit I do not prefer any one of them. So which equality should be
used to test whether the variable is equal to the matched part of the
value?

I guess this simple question is one of the reasons why such a feature is
not in the language up to now.

Gerd
-- 
------------------------------------------------------------
Gerd Stolpmann * Viktoriastr. 45 * 64293 Darmstadt * Germany 
gerd@gerd-stolpmann.de          http://www.gerd-stolpmann.de
Phone: +49-6151-153855                  Fax: +49-6151-997714
------------------------------------------------------------


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [Caml-list] Patterns that evaluate
  2007-02-14 18:55     ` Gerd Stolpmann
@ 2007-02-14 19:10       ` Denis Bueno
  2007-02-14 19:11       ` Jacques Carette
  2007-02-14 21:05       ` Jon Harrop
  2 siblings, 0 replies; 22+ messages in thread
From: Denis Bueno @ 2007-02-14 19:10 UTC (permalink / raw)
  To: Gerd Stolpmann; +Cc: Edgar Friendly, caml-list

On 2/14/07, Gerd Stolpmann <info@gerd-stolpmann.de> wrote:
> You are a bit quick. Before discussing syntax it is more important to
> define the semantics of such patterns. I mean we have already three
> predefined kinds of equality in O'Caml:
>
> - ( == )
> - ( = )
> - (fun x y -> compare x y = 0)
>
> I admit I do not prefer any one of them. So which equality should be
> used to test whether the variable is equal to the matched part of the
> value?
>
> I guess this simple question is one of the reasons why such a feature is
> not in the language up to now.

I agree with Gerd: equality is a hard thing to get right.

For many months now I have been working on a compiler for a constraint
solving language, and I always need to spend a significant amount of
time, after the creation of each data structure, defining comparisons
on instances of those structures. Usually there is one that defines an
ordering for the purpose of using instances as keys in a Map; and
sometimes there are additional equivalence relations that compare
different aspects of structures.

The principle then, applied to this problem, is: immediately *someone*
is going to need a comparison function other than the ones above. And
if there is no support for such functions, many people will consider
the feature useless for all but the simplest of tasks. If there is
support, it will become a question of just how convenient that support
is.

These aren't necessarily un-answerable questions; but they are not easy.

-Denis


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [Caml-list] Patterns that evaluate
  2007-02-14 18:55     ` Gerd Stolpmann
  2007-02-14 19:10       ` Denis Bueno
@ 2007-02-14 19:11       ` Jacques Carette
  2007-02-14 19:25         ` Gerd Stolpmann
  2007-02-14 21:05       ` Jon Harrop
  2 siblings, 1 reply; 22+ messages in thread
From: Jacques Carette @ 2007-02-14 19:11 UTC (permalink / raw)
  To: caml-list; +Cc: Gerd Stolpmann

Gerd Stolpmann wrote:
> Before discussing syntax it is more important to
> define the semantics of such patterns. I mean we have already three
> predefined kinds of equality in O'Caml:
>
> - ( == )
> - ( = )
> - (fun x y -> compare x y = 0)
>
> I admit I do not prefer any one of them. So which equality should be
> used to test whether the variable is equal to the matched part of the
> value?
>   

I would definitely favour structural equality, since that meshes well 
with pattern-matching's semantics.  Anything else would seem hard to 
justify, but that's just my opinion.

Jacques


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [Caml-list] Patterns that evaluate
  2007-02-14 19:11       ` Jacques Carette
@ 2007-02-14 19:25         ` Gerd Stolpmann
  2007-02-14 20:30           ` Edgar Friendly
  0 siblings, 1 reply; 22+ messages in thread
From: Gerd Stolpmann @ 2007-02-14 19:25 UTC (permalink / raw)
  To: Jacques Carette; +Cc: caml-list

Am Mittwoch, den 14.02.2007, 14:11 -0500 schrieb Jacques Carette:
> Gerd Stolpmann wrote:
> > Before discussing syntax it is more important to
> > define the semantics of such patterns. I mean we have already three
> > predefined kinds of equality in O'Caml:
> >
> > - ( == )
> > - ( = )
> > - (fun x y -> compare x y = 0)
> >
> > I admit I do not prefer any one of them. So which equality should be
> > used to test whether the variable is equal to the matched part of the
> > value?
> >   
> 
> I would definitely favour structural equality, since that meshes well 
> with pattern-matching's semantics.  Anything else would seem hard to 
> justify, but that's just my opinion.

It is easy to have another opinion (and that's the basic problem). There
is a good reason to prefer physical equality: pattern matching
decomposes physically anyway, so this equality looks more natural. On
the other hand, the existing string matching (match s with "literal")
compares string contents. 

It is already a mess.

Gerd
-- 
------------------------------------------------------------
Gerd Stolpmann * Viktoriastr. 45 * 64293 Darmstadt * Germany 
gerd@gerd-stolpmann.de          http://www.gerd-stolpmann.de
Phone: +49-6151-153855                  Fax: +49-6151-997714
------------------------------------------------------------


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [Caml-list] Patterns that evaluate
  2007-02-13 22:04 Patterns that evaluate Jacques Carette
  2007-02-13 22:07 ` [Caml-list] " Jon Harrop
@ 2007-02-14 20:29 ` Nathaniel Gray
  2007-02-14 21:10   ` Jacques Carette
  1 sibling, 1 reply; 22+ messages in thread
From: Nathaniel Gray @ 2007-02-14 20:29 UTC (permalink / raw)
  To: Jacques Carette; +Cc: OCaml

On 2/13/07, Jacques Carette <carette@mcmaster.ca> wrote:
> I recently wrote some ocaml code which "worked", but not as I
> intended...  The test cases I tried worked, but I should have tested
> harder.  Apparently I was under the mistaken impression that OCaml's
> pattern-matching was more "first class"!  So I wrote (in part):
>
> let buildsimp cast e f1 f2 = fun e1 -> fun e2 -> match (e1,e2) with
>                                                  | ({st = Some e}, _) -> e2
>
> and I expected it to work.  Only a code review by a colleague 'found'
> this bug in my code.

I guess I'm not seeing it.  How did you expect it to work?  Is this
what you mean:

... | ({st = Some v}, _) when v = e -> e2

Is there some functionality that you're looking for that when clauses
don't provide?

Cheers,
-n8

-- 
>>>-- Nathaniel Gray -- Caltech Computer Science ------>
>>>-- Mojave Project -- http://mojave.cs.caltech.edu -->


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [Caml-list] Patterns that evaluate
  2007-02-14 19:25         ` Gerd Stolpmann
@ 2007-02-14 20:30           ` Edgar Friendly
  0 siblings, 0 replies; 22+ messages in thread
From: Edgar Friendly @ 2007-02-14 20:30 UTC (permalink / raw)
  To: Gerd Stolpmann; +Cc: Jacques Carette, caml-list

Gerd Stolpmann wrote:
> Am Mittwoch, den 14.02.2007, 14:11 -0500 schrieb Jacques Carette:
>> Gerd Stolpmann wrote:
>>> Before discussing syntax it is more important to
>>> define the semantics of such patterns. I mean we have already three
>>> predefined kinds of equality in O'Caml:
>>>
>>> - ( == )
>>> - ( = )
>>> - (fun x y -> compare x y = 0)
>>>
>>> I admit I do not prefer any one of them. So which equality should be
>>> used to test whether the variable is equal to the matched part of the
>>> value?
>>>   
>> I would definitely favour structural equality, since that meshes well 
>> with pattern-matching's semantics.  Anything else would seem hard to 
>> justify, but that's just my opinion.
> 
> It is easy to have another opinion (and that's the basic problem). There
> is a good reason to prefer physical equality: pattern matching
> decomposes physically anyway, so this equality looks more natural. On
> the other hand, the existing string matching (match s with "literal")
> compares string contents. 
> 
> It is already a mess.
> 
> Gerd

If I have to, I think I can satisfy both structural and physical 
equality with different tokens:

If you want:
* structural equality, use |= to prefix the pattern case
* physical equality, use |== to prefix the pattern case
* something else, use | and when to specify whatever explicit guard you 
want.

Does this satisfy all parties?

E.


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [Caml-list] Patterns that evaluate
  2007-02-14 18:55     ` Gerd Stolpmann
  2007-02-14 19:10       ` Denis Bueno
  2007-02-14 19:11       ` Jacques Carette
@ 2007-02-14 21:05       ` Jon Harrop
  2007-02-14 21:33         ` Jacques Carette
  2 siblings, 1 reply; 22+ messages in thread
From: Jon Harrop @ 2007-02-14 21:05 UTC (permalink / raw)
  Cc: caml-list

On Wednesday 14 February 2007 18:55, Gerd Stolpmann wrote:
> You are a bit quick. Before discussing syntax it is more important to
> define the semantics of such patterns. I mean we have already three
> predefined kinds of equality in O'Caml:
>
> - ( == )
> - ( = )
> - (fun x y -> compare x y = 0)
>
> I admit I do not prefer any one of them. So which equality should be
> used to test whether the variable is equal to the matched part of the
> value?

None, I think.

Pattern matching is clearly an awesome tool, and there are many ways that 
OCaml's pattern matching can be improved upon. To me, active patterns are 
about applying user-defined functions to test partial matches. So I would 
want the user to explicitly supply the appropriate comparison function, as 
you do with Set and Map.

There are many places where this is advantageous. My favourite example is term 
rewriting.

Assuming the existence of +: and *: operators to add and multiply symbolic 
expressions, we can currently write a symbolic derivative function:

let rec d f x = match f with
  | Var y when x=y -> Int 1
  | Int _ | Var _ -> Int 0
  | Add(f, g) -> d f x +: d g x
  | Mul(f, g) -> f *: d g x +: g *: d f x

That is already nicer than most other languages but there is plenty of room 
for improvement.

Before we even get to active patterns, we can add operator overloading to use 
+ and * instead:

let rec d f x = match f with
  | Var y when x=y -> Int 1
  | Int _ | Var _ -> Int 0
  | Add(f, g) -> d f x + d g x
  | Mul(f, g) -> f * d g x + g * d f x

That's a bit better. Why not have infix operators as constructors and 
deconstructors:

let rec d f x = match f with
  | Var y when x=y -> Int 1
  | Int _ | Var _ -> Int 0
  | f + g -> d f x + d g x
  | f * g -> f * d g x + g * d f x

But we often want more than that. Consider a function that naively performs 
the substitution a+b -> c taking commutativity into account:

let rec mem x = function
  | Int _ | Var _ as f -> f=x
  | Add(f, g) | Mul(f, g) as e -> mem_rec e x f || mem_rec e x g
and mem_rec e x f = match e, f with
  | Add _, Add _ | Mul _, Mul _ -> mem x f
  | Add _, _ | Mul _, _ -> false
  | _ -> assert false

let rec sub = function
  | Int _ | Var _ as f -> f
  | Add _ as e when mem (Var "a") e && mem (Var "b") e ->
      Var "c" +: sub(e -: Var "a" -: Var "b")
  | Add(f, g) -> Add(sub f, sub g)
  | Mul(f, g) -> Mul(sub f, sub g)

That could be written much more elegantly, something like this:

let rec rewrite rule = function
  | Int _ | Var _ as f -> rule f
  | Add(f, g) -> Add(rewrite rule f, rewrite rule g)
  | Mul(f, g) -> Mul(rewrite rule f, rewrite rule g)

let sub = function
  | Var "a" + Var "b" + t -> Var "c" + t
  | expr -> expr

let sub = rewrite sub

where the pattern Var "a" + Var "b" + t searches the symbolic expression 
for "a" and "b" and puts the remainder in t. So the "+" is an active pattern 
that takes two patterns as arguments and matches if it can split an 
expression into an addition of the two patterns. This active pattern can then 
be made arbitrarily clever with respect to how it slices and dices the data 
structure. Better yet, the code is no longer tied to the underlying 
representation of terms, so the inefficient representation of a sum as a list 
of Add cells can be replaced by a mapping from terms to their multiples, 
which can then be searched in O(log n) time instead of O(n) time.

Given that these kinds of ideas have been around for so long (that Haskell 
views paper), I'm surprised that people have implemented active patterns in 
more languages.

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [Caml-list] Patterns that evaluate
  2007-02-14 20:29 ` Nathaniel Gray
@ 2007-02-14 21:10   ` Jacques Carette
  2007-02-15  3:53     ` skaller
  2007-02-15 20:43     ` Nathaniel Gray
  0 siblings, 2 replies; 22+ messages in thread
From: Jacques Carette @ 2007-02-14 21:10 UTC (permalink / raw)
  To: Nathaniel Gray; +Cc: OCaml

Nathaniel Gray wrote:
> On 2/13/07, Jacques Carette <carette@mcmaster.ca> wrote:
>> So I wrote (in part):
>>
>> let buildsimp cast e f1 f2 = fun e1 -> fun e2 -> match (e1,e2) with
>>                                                  | ({st = Some e}, _) 
>> -> e2
>>
>> and I expected it to work.  Only a code review by a colleague 'found'
>> this bug in my code.
>
> I guess I'm not seeing it.  How did you expect it to work?  Is this
> what you mean:
>
> ... | ({st = Some v}, _) when v = e -> e2
Yes. that is what I meant.

> Is there some functionality that you're looking for that when clauses
> don't provide?
No, there is not.  I was just (mistakenly) assuming that the "more 
pleasant" syntax for this ``worked''.

Explanation: when I was a language designer, I learned a lot from user 
'mistakes' like this.  Such mistakes told me of the mismatch between 
user expectations and current reality.  So I try to take the time to 
document my own 'mistakes'. 
Philosophy: if I don't take the time to give feedback, why should I 
expect users of my own work to be any different?

Jacques

PS: there is no real functionality that I am looking for that Turing 
Machines don't provide (or C or Java or ...).  And yet I prefer 
languages like (Meta)OCaml and Haskell.  The "raw functionality" 
argument does not seem to be the optimal way to look at these issues, IMHO.


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [Caml-list] Patterns that evaluate
  2007-02-14 21:05       ` Jon Harrop
@ 2007-02-14 21:33         ` Jacques Carette
  0 siblings, 0 replies; 22+ messages in thread
From: Jacques Carette @ 2007-02-14 21:33 UTC (permalink / raw)
  To: Jon Harrop; +Cc: caml-list

[Many excellent ideas on Active Patterns removed]

Jon Harrop wrote:
> That could be written much more elegantly, something like this:
>
> let rec rewrite rule = function
>   | Int _ | Var _ as f -> rule f
>   | Add(f, g) -> Add(rewrite rule f, rewrite rule g)
>   | Mul(f, g) -> Mul(rewrite rule f, rewrite rule g)
>   
Following ideas of Barry Jay, this could be even more simply written as
let rec rewrite rule = function
  | u _ as f -> rule f
  | b(f, g) -> b(rewrite rule f, rewrite rule g)

where u and b are supposed to be bound (to respectively unary and binary 
constructors).

Yes, the 'type' of the function rewrite needs higher-order polymorphism 
(or polytypism or ...) to work.  See Tim Sheard's Omega for one rather 
nice way to do that.

Jacques


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [Caml-list] Patterns that evaluate
  2007-02-13 22:07 ` [Caml-list] " Jon Harrop
  2007-02-14  0:10   ` Jacques Carette
  2007-02-14 18:20   ` Edgar Friendly
@ 2007-02-14 22:34   ` Martin Jambon
  2007-02-15  0:26     ` Jacques Garrigue
  2 siblings, 1 reply; 22+ messages in thread
From: Martin Jambon @ 2007-02-14 22:34 UTC (permalink / raw)
  To: Jon Harrop; +Cc: caml-list

On Tue, 13 Feb 2007, Jon Harrop wrote:

> On Tuesday 13 February 2007 22:04, Jacques Carette wrote:
> > I recently wrote some ocaml code which "worked", but not as I
> > intended...  The test cases I tried worked, but I should have tested
> > harder.  Apparently I was under the mistaken impression that OCaml's
> > pattern-matching was more "first class"!  So I wrote (in part):
> >
> > let buildsimp cast e f1 f2 = fun e1 -> fun e2 -> match (e1,e2) with
> >
> >                                                  | ({st = Some e}, _) -> e2
> >
> > and I expected it to work.  Only a code review by a colleague 'found'
> > this bug in my code.
> >
> > Question: would it be a difficult extension?  This seemed so "natural",
> > I just "used" the feature before it was quite there yet ;-).
>
> F# just introduced active patterns, which does what you want AFAIK. Of course,
> you must disambiguate that from the OCaml's current interpretation of the
> above (binding "e").

That's funny, I posted a syntax extension that does that one week ago,
but I didn't know it was already implemented in F#.
http://caml.inria.fr/pub/ml-archives/caml-list/2007/02/e397c716c448a0aeff92b7af709bb1b4.en.html
http://blogs.msdn.com/dsyme/archive/2006/08/16/ActivePatterns.aspx

"Active patterns" seems to be another name for "simple views" or
vice-versa.

It converged to an extremely similar solution, so it must be a good one
:-)

It doesn't solve the original problem though, which IMHO is better solved
with a standard "when" guard as mentioned earlier.



Martin

--
Martin Jambon
http://martin.jambon.free.fr


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [Caml-list] Patterns that evaluate
  2007-02-14 22:34   ` Martin Jambon
@ 2007-02-15  0:26     ` Jacques Garrigue
  2007-02-15  3:57       ` Jon Harrop
  0 siblings, 1 reply; 22+ messages in thread
From: Jacques Garrigue @ 2007-02-15  0:26 UTC (permalink / raw)
  To: martin.jambon; +Cc: caml-list

From: Martin Jambon <martin.jambon@ens-lyon.org>
> On Tue, 13 Feb 2007, Jon Harrop wrote:
> > On Tuesday 13 February 2007 22:04, Jacques Carette wrote:
> > > I recently wrote some ocaml code which "worked", but not as I
> > > intended...  The test cases I tried worked, but I should have tested
> > > harder.  Apparently I was under the mistaken impression that OCaml's
> > > pattern-matching was more "first class"!  So I wrote (in part):
> > >
> > > let buildsimp cast e f1 f2 = fun e1 -> fun e2 -> match (e1,e2) with
> > >
> > >                                           | ({st = Some e}, _) -> e2
> > >
> > > and I expected it to work.  Only a code review by a colleague 'found'
> > > this bug in my code.
> > >
> > > Question: would it be a difficult extension?  This seemed so "natural",
> > > I just "used" the feature before it was quite there yet ;-).
> >
> > F# just introduced active patterns, which does what you want AFAIK. Of course,
> > you must disambiguate that from the OCaml's current interpretation of the
> > above (binding "e").
> 
> That's funny, I posted a syntax extension that does that one week ago,
> but I didn't know it was already implemented in F#.
> http://caml.inria.fr/pub/ml-archives/caml-list/2007/02/e397c716c448a0aeff92b7af709bb1b4.en.html
> http://blogs.msdn.com/dsyme/archive/2006/08/16/ActivePatterns.aspx
> 
> "Active patterns" seems to be another name for "simple views" or
> vice-versa.
> 
> It converged to an extremely similar solution, so it must be a good one
> :-)
> 
> It doesn't solve the original problem though, which IMHO is better solved
> with a standard "when" guard as mentioned earlier.

Martin, I think you have a lot of good points here.
"when" clauses were exactly introduced in order to solve this kind of
problems.
However, I agree with the other Jacques that reusing an existing
variable in a pattern-matching is a common error, so it might be a
good idea to have a warning for that. Unused variable warnings were
introduced relatively recently, and there is still work to do on
misuse of variables. Note that reusing variable names is a common
idiom, so we don't want to disallow it completely, but "masking a
local variable in a pattern matching with several branches", as done
above, looks like something very suspicious.

The other question is on views. They could maybe help in this case,
using a parameterized view that checks equality with it parameter, but
this seems far-fetched. However, they have plenty of other
applications where they would be very useful.

As with any extension, an important question with views is whether
they should be in the language, as in F#, or supported by the
preprocessor as you did. After all, pattern-matching in Scheme is
entirely based on macros, and people are perfectly happy with
that. Why is it not the case in ML? Because, thanks to typing, we can
check exhaustivity and overlapping, and use this information to detect
error and optimize compilation. Unfortunately, views do not allow
that, so there seems to be less incentive to make them a core
feature. There was a lot written about the need for views to be proved
bijective before they can be mixed freely with pattern-matching, but
such proof doesn't seem practical for now.
This may explain why, while they look like a natural extension of
pattern-matching, they are not a standard feature.

Jacques Garrigue


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [Caml-list] Patterns that evaluate
  2007-02-14 21:10   ` Jacques Carette
@ 2007-02-15  3:53     ` skaller
  2007-02-15 13:41       ` Jacques Carette
  2007-02-15 20:43     ` Nathaniel Gray
  1 sibling, 1 reply; 22+ messages in thread
From: skaller @ 2007-02-15  3:53 UTC (permalink / raw)
  To: Jacques Carette; +Cc: Nathaniel Gray, OCaml

On Wed, 2007-02-14 at 16:10 -0500, Jacques Carette wrote:
> Nathaniel Gray wrote:

> > I guess I'm not seeing it.  How did you expect it to work?  Is this
> > what you mean:
> >
> > ... | ({st = Some v}, _) when v = e -> e2
> Yes. that is what I meant.
> 
> > Is there some functionality that you're looking for that when clauses
> > don't provide?
> No, there is not.  I was just (mistakenly) assuming that the "more 
> pleasant" syntax for this ``worked''.

It is a common wish, but has many problems IMHO.

First, it isn't very general. When clause has form:

	  | ... x ... when P(x) ->

which can express a lot more than merely one of the three
equality operators. Indeed, P doesn't even have to be a
known function -- it can be a function value.

Second, the translation:

	| .. e .. ->   to | .. x .. when x = e -> 

without extra lexical marks distinguishing
pattern variables from local variables, and more generally
patterns from expressions, would be extremely fragile:

	let h = 1 in 
	match x with
	| h :: t -> ...

The meaning of this matching appears to be to match
a list starting with 1, binding t to the tail .. but
it all depends on whether t is a symbol in the context
of this fragment. The meaning would change if t were
not in the context and a programmer introduced it:

(* no t here *)
....
let ...

     | h :: t ->

Now the programmer adds a new global variable

let t = [2]

...


and it changes the meaning of the implementation of
a function which one would expect was abstracted and localised.

Thirdly it leaves open the issue of non-linear patterns:

	| x , x -> ...

The first x binds to the first component of a tuple ..
what does the second x do?? Easily solved with a when
clause:

	| x, y when x = y -> ...

Fourth, when clauses have a restriction that they do not
allow introduction of extra bindings. I often need that:

	| C  x | D with x = 1 -> ... x ....

where I'm introducing a default for one branch. 
I also often match nasty patterns in many places and really
wish I could name them:

	pattern p(x) = C x
	match e with | p(x) -> ...

doesn't provide active patterns, but it would be quite useful.
This can be done with a match composition already too:

	let p e = 
		try match e with C x -> x 
		with _ -> raise MatchFailure
	..
	try let x = p e in ..with MatchFailure -> (* next case *)

but it is messy (hard to compose).

Jacques said:

> Is there some functionality that you're looking for that when clauses
> > don't provide?
> No, there is not.

and that's basically wrong. He's not telling the truth here :-> 
He IS looking for something more general, specifically

	| f a -> ..

where f is pattern match variable. Ocaml currently requires f to be
a constructor, that is, a constant. Any notion of advanced
pattern matching would have to allow match variables to bind
to constructors. 

IF we're going to extend pattern matching it should do this:

http://www-staff.it.uts.edu.au/~cbj/Publications/pattern_calculus.ps

IMHO of course.. :)

-- 
John Skaller <skaller at users dot sf dot net>
Felix, successor to C++: http://felix.sf.net


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [Caml-list] Patterns that evaluate
  2007-02-15  0:26     ` Jacques Garrigue
@ 2007-02-15  3:57       ` Jon Harrop
  2007-02-15 22:43         ` Don Syme
  0 siblings, 1 reply; 22+ messages in thread
From: Jon Harrop @ 2007-02-15  3:57 UTC (permalink / raw)
  To: caml-list

On Thursday 15 February 2007 00:26, Jacques Garrigue wrote:
> As with any extension, an important question with views is whether
> they should be in the language, as in F#, or supported by the
> preprocessor as you did. After all, pattern-matching in Scheme is
> entirely based on macros, and people are perfectly happy with
> that. Why is it not the case in ML? Because, thanks to typing, we can
> check exhaustivity and overlapping, and use this information to detect
> error and optimize compilation. Unfortunately, views do not allow
> that...

Actually, I believe F# implements that in some form.

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [Caml-list] Patterns that evaluate
  2007-02-15  3:53     ` skaller
@ 2007-02-15 13:41       ` Jacques Carette
  2007-02-15 14:10         ` skaller
  0 siblings, 1 reply; 22+ messages in thread
From: Jacques Carette @ 2007-02-15 13:41 UTC (permalink / raw)
  To: skaller; +Cc: OCaml

skaller wrote:
> It is a common wish, but has many problems IMHO.
> First, it isn't very general. 
Fallacious argument: OCaml has records, so there is no need for tuples 
which are less general.  Yet it has them. 
The point is to balance generality with convenience.  That is why 
redundancy in a language may be a pain for the compiler writers, but can 
make a big difference to the users.

Note that I was not suggesting, ever, that OCaml's current 
pattern-matching be 'broken' by blindly adding 'active' views.  A 
different syntax would seem to make sense. 

> [...] and more generally
> patterns from expressions, would be extremely fragile:
>
> 	let h = 1 in 
> 	match x with
> 	| h :: t -> ...
>
> The meaning of this matching appears to be to match
> a list starting with 1, binding t to the tail .. but
> it all depends on whether t is a symbol in the context
> of this fragment. The meaning would change if t were
> not in the context and a programmer introduced it:
>   
Sure.  But that is the normal semantics of the rest of OCaml you're 
complaining about here!  Yes, having a pattern-matching mechanism which 
is context dependent (like the rest of OCaml) instead of always working 
in an empty environment is different, that is expected.

Personally, I find that I don't write programs with a lot of variable 
shadowing, I tend to use new names in matches.  And no globals.  I 
consider them both to be bad style ;-)


> Thirdly it leaves open the issue of non-linear patterns:
> 	| x , x -> ...
>   
If x had a value, this would not be a problem at all.  It is only a 
problem in the 'binding' case.

> I also often match nasty patterns in many places and really
> wish I could name them:
>
> 	pattern p(x) = C x
> 	match e with | p(x) -> ...
>
> doesn't provide active patterns, but it would be quite useful.
>   
Agreed, that would be nice.

Regarding Jay-style matching: I was _expecting_ some kind of active 
patterns to work, I _want_ Jay style patterns.  Very different!

Jacques


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [Caml-list] Patterns that evaluate
  2007-02-15 13:41       ` Jacques Carette
@ 2007-02-15 14:10         ` skaller
  0 siblings, 0 replies; 22+ messages in thread
From: skaller @ 2007-02-15 14:10 UTC (permalink / raw)
  To: Jacques Carette; +Cc: OCaml

On Thu, 2007-02-15 at 08:41 -0500, Jacques Carette wrote:
> skaller wrote:
> > It is a common wish, but has many problems IMHO.
> > First, it isn't very general. 
> Fallacious argument: OCaml has records, so there is no need for tuples 
> which are less general.  Yet it has them. 

It isn't an argument, it's a bullet point.

> The point is to balance generality with convenience.  

Yes, I agree.

> > patterns from expressions, would be extremely fragile:

> Sure.  But that is the normal semantics of the rest of OCaml you're 
> complaining about here! 

That's only partly true. In much of ocaml, you can use local
construction such as 

	let x = expr in expr

which names the variable 'x' to be used in 'expr'. There are
issues of hijacking of course. However with the pattern thing,
the issue is not *which* definition of x you're referring to,
but whether you're referring to one at all -- or actually
introducing one.

Current patterns have two name classes: pattern match variables
(lower case first letter) and constructors (upper case first
letter or backtick for polymorphic variants, or perhaps
a #term for them).

Adding a third category suggests a new lexical mark, to keep
the 'kind' of the symbol lexically determinate.

[Yes, I know Ocaml implicitly introduces variables not
only in patterns .. but also type variables]

-- 
John Skaller <skaller at users dot sf dot net>
Felix, successor to C++: http://felix.sf.net


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [Caml-list] Patterns that evaluate
  2007-02-14 21:10   ` Jacques Carette
  2007-02-15  3:53     ` skaller
@ 2007-02-15 20:43     ` Nathaniel Gray
  2007-03-07 11:15       ` Oliver Bandel
  1 sibling, 1 reply; 22+ messages in thread
From: Nathaniel Gray @ 2007-02-15 20:43 UTC (permalink / raw)
  To: Jacques Carette; +Cc: OCaml

On 2/14/07, Jacques Carette <carette@mcmaster.ca> wrote:
> Nathaniel Gray wrote:
> > On 2/13/07, Jacques Carette <carette@mcmaster.ca> wrote:
> >> So I wrote (in part):
> >>
> >> let buildsimp cast e f1 f2 = fun e1 -> fun e2 -> match (e1,e2) with
> >>                                                  | ({st = Some e}, _)
> >> -> e2
> >>
> >> and I expected it to work.  Only a code review by a colleague 'found'
> >> this bug in my code.
> >
> > I guess I'm not seeing it.  How did you expect it to work?  Is this
> > what you mean:
> >
> > ... | ({st = Some v}, _) when v = e -> e2
> Yes. that is what I meant.
>
> > Is there some functionality that you're looking for that when clauses
> > don't provide?
> No, there is not.  I was just (mistakenly) assuming that the "more
> pleasant" syntax for this ``worked''.
>
> Explanation: when I was a language designer, I learned a lot from user
> 'mistakes' like this.  Such mistakes told me of the mismatch between
> user expectations and current reality.  So I try to take the time to
> document my own 'mistakes'.
> Philosophy: if I don't take the time to give feedback, why should I
> expect users of my own work to be any different?

That's fine.  I just wasn't sure what you expected to happen.  I made
the same mistake myself when I was learning OCaml, but I don't think
it's something that should be changed.  It's good to minimize new user
mistakes, but you need to make a distinction between mistakes that new
users make once and never make again versus those that cause ongoing
grief.  I think this is definitely the former.  It only takes one
"bite" to make you understand that pattern matches don't compute.

One potential "solution" to this problem for new users would be a
compiler warning when you shadow an existing variable in an explicit
pattern match.

> PS: there is no real functionality that I am looking for that Turing
> Machines don't provide (or C or Java or ...).  And yet I prefer
> languages like (Meta)OCaml and Haskell.  The "raw functionality"
> argument does not seem to be the optimal way to look at these issues, IMHO.

Maybe, but the "it's all equivalent to Turing machines" argument is
pointless outside of formal proofs.  Proposing some syntactic sugar
for 'when' clauses is a very different thing from, say, proposing type
classes and operator overloading, even though neither one has any
impact on what the language can compute.

Cheers,
-n8

-- 
>>>-- Nathaniel Gray -- Caltech Computer Science ------>
>>>-- Mojave Project -- http://mojave.cs.caltech.edu -->


^ permalink raw reply	[flat|nested] 22+ messages in thread

* RE: [Caml-list] Patterns that evaluate
  2007-02-15  3:57       ` Jon Harrop
@ 2007-02-15 22:43         ` Don Syme
  0 siblings, 0 replies; 22+ messages in thread
From: Don Syme @ 2007-02-15 22:43 UTC (permalink / raw)
  To: Jon Harrop, caml-list

> > Because, thanks to typing, we can
> > check exhaustivity and overlapping, and use this information to detect
> > error and optimize compilation. Unfortunately, views do not allow
> > that...
>
> Actually, I believe F# implements that in some form.

Jon's jumping the gun a little: we have indeed recently redesigned active patterns for F# and I'll be writing up the details in the next few days, in a blog entry I guess. The implementation will also be in the next F# release.

There are still plenty of issues with using active patterns, especially in languages with side effects - how many times do you run those discrimination functions? Possible approaches to this issue were addressed by Chris Okasaki's paper on views for Standard ML, and the current specification we're using for F# is that "if we need to run an active discrimination function on a given input once, we can run it on the same input as many times as we wish within the given pattern match".  That is somewhat unsatisfactory semantically if the functions have visible side effects, but we want to strongly discourage such discriminator functions, in much the same way that side effects are strongly discouraged by the functions that implement the C# and F# property notations.  So I believe will be OK in practice, though I can see why people might find it distasteful (though if you don't choose this semantics then exponential code blow up looks hard to avoid, including in realistic code).

In any case our main aim has really been to explore the design space and find out how useful these things actually are in practice, and see if there's a reasonable version of this stuff that might make it into C# or a similar language.

BTW this work was done by Gregory Neverov over last summer during his internship at MSR. This led to me discussing the issue with a bunch of functional languages folk, including Martin Odersky, who was looking at the issue in Scala, along with Burak Emir.  Then I showed Greg's prototype to Simon Peyton Jones, which led to him making a proposal for views for Haskell, which led to Martin Jambon looking at the issue from the OCaml perspective (and going beyond what we had in the F# prototype in some interesting ways).

Cheers
don




-----Original Message-----
From: caml-list-bounces@yquem.inria.fr [mailto:caml-list-bounces@yquem.inria.fr] On Behalf Of Jon Harrop
Sent: 15 February 2007 03:58
To: caml-list@yquem.inria.fr
Subject: Re: [Caml-list] Patterns that evaluate

On Thursday 15 February 2007 00:26, Jacques Garrigue wrote:
> As with any extension, an important question with views is whether
> they should be in the language, as in F#, or supported by the
> preprocessor as you did. After all, pattern-matching in Scheme is
> entirely based on macros, and people are perfectly happy with
> that. Why is it not the case in ML? Because, thanks to typing, we can
> check exhaustivity and overlapping, and use this information to detect
> error and optimize compilation. Unfortunately, views do not allow
> that...

Actually, I believe F# implements that in some form.

--
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists

_______________________________________________
Caml-list mailing list. Subscription management:
http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list
Archives: http://caml.inria.fr
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
Bug reports: http://caml.inria.fr/bin/caml-bugs


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [Caml-list] Patterns that evaluate
  2007-02-15 20:43     ` Nathaniel Gray
@ 2007-03-07 11:15       ` Oliver Bandel
  0 siblings, 0 replies; 22+ messages in thread
From: Oliver Bandel @ 2007-03-07 11:15 UTC (permalink / raw)
  To: OCaml

On Thu, Feb 15, 2007 at 12:43:22PM -0800, Nathaniel Gray wrote:
[...]
> One potential "solution" to this problem for new users would be a
> compiler warning when you shadow an existing variable in an explicit
> pattern match.
[...]

Shadowing an existing "variable": isn't this the normal way how FPLs
"do it"?

It's: the inner (local) environment overwrites the outer environments
and that's, how FPLs are doing it. A new binding to a name.

Should all re-bindings be worth a warning?
if not: which should create a warning, which not?

Is this necessary in pattern matches only?

Ciao,
   Oliver


^ permalink raw reply	[flat|nested] 22+ messages in thread

end of thread, other threads:[~2007-03-07 11:15 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-02-13 22:04 Patterns that evaluate Jacques Carette
2007-02-13 22:07 ` [Caml-list] " Jon Harrop
2007-02-14  0:10   ` Jacques Carette
2007-02-14 18:20   ` Edgar Friendly
2007-02-14 18:55     ` Gerd Stolpmann
2007-02-14 19:10       ` Denis Bueno
2007-02-14 19:11       ` Jacques Carette
2007-02-14 19:25         ` Gerd Stolpmann
2007-02-14 20:30           ` Edgar Friendly
2007-02-14 21:05       ` Jon Harrop
2007-02-14 21:33         ` Jacques Carette
2007-02-14 22:34   ` Martin Jambon
2007-02-15  0:26     ` Jacques Garrigue
2007-02-15  3:57       ` Jon Harrop
2007-02-15 22:43         ` Don Syme
2007-02-14 20:29 ` Nathaniel Gray
2007-02-14 21:10   ` Jacques Carette
2007-02-15  3:53     ` skaller
2007-02-15 13:41       ` Jacques Carette
2007-02-15 14:10         ` skaller
2007-02-15 20:43     ` Nathaniel Gray
2007-03-07 11:15       ` Oliver Bandel

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).