skaller wrote:
>> 2. views/active patterns
>>
>> see
>> http://blogs.msdn.com/dsyme/archive/2007/04/06/detailed-release-notes-for-1-9-1-8.aspx.
>>
>>
>> This lets you extend pattern matching so that you can create virtual
>> constructors to match against.
>
> Felix has had 'virtual' fields for ages.
I think you misunderstood me. Active patterns allow you to define fake
constructors that you can match against using traditional pattern
matching techniques. To adapt one of the examples into something
felix-like, it'd be like this:
say we had these functions for extracting the components of a complex
number:
fun real_part (x:complex):float = ...;
fun imag_part (x:complex):float = ...;
fun magnitude (x:complex):float = ...;
fun phase (x:complex):float = ...;
fun mk_from_rect (x:float, y:float):complex = ...;
fun mk_from_polar (x:float, y:float):complex = ...;
then we'd define the virtual pattern (I'll explain this syntax in a sec):
union RectPattern
| Rect of float*float
;
union PolarPattern
| Polar of float*float
;
fun _pattern_RectPattern (x:complex) => Rect (real_part x, imag_part x);
fun _pattern_PolarPattern (x:complex) => Polar (magnitude x, phase x);
finally, we could use this in a match, like this:
fun mulViaRect (c1:complex) (c2:complex) =>
match c1, c2 with
| Rect(?ar, ?ai), Rect(?br, ?bi) => mk_from_rect (ar*br - ai*bi, ai*br
+ ar*bi)
endmatch
;
fun mulViaPolar (c1:complex) (c2:complex) =>
match c1, c2 with
| Polar(?r1, ?th1), Polar(?r2, ?th2) => mk_from_polar (r1*r2, th1+th2)
endmatch
;
This would just be sugar for:
fun mulViaRect (c1:complex) (c2:complex) = {
val p1 = Rect (real_part c1, imag_part c1);
val p2 = Rect (real_part c2, imag_part c2);
return
match p1, p2 with
| Rect(?ar, ?ai), Rect(?br, ?bi) => mk_from_rect (ar*br - ai*bi,
ai*br + ar*bi)
endmatch
;
}
fun mulViaPolar (c1:complex) (c2:complex) = {
val p1 = Polar (magnitude c1, phase c1);
val p2 = Polar (magnitude c2, phase c2);
return
match p1, p2 with
| Polar(?r1, ?th1), Polar(?r2, ?th2) => mk_from_polar (r1*r2, th1+th2)
endmatch
;
}
Since F# allows destructuring in many places, you can do things like (in
felix-like):
iter (proc (Polar (?r, ?th)) {
print f"r = %f, th = %f\n" (r, th);
} complexNumberList;
Which would just be sugar for:
iter (proc (c:complex) {
val r, th = (magnitude c, phase c);
print f"r = %f, th = %f\n" (r, th);
} complexNumberList;
Since these patterns are one-to-one, all possible matches must be handled.
The reason why they list the virtual constructor twice is to support
aggregate and partial matching. Here's an aggregation example. The set
of virtual patterns is defined as a union we can then return from the
pattern:
union Pattern
| Under6 of int
| Six
| Over6 of int
;
fun _pattern_SixPattern (x:int) =>
if x < 6 then
Under6 x
elif x > 6 then
Over6 x
else
Six
;
we could then use this like this:
fun foo (x:int) =>
match x with
| Under6 ?y => f"under six: %d" y
| Six => "six"
| Over6 ?z => f"over six: %d" z
endmatch
;
As usual, this is sugar for:
fun foo (x:int) = {
val p =
if x < 6 then
Under6 x
elif x > 6 then
Over6 x
else
Six
;
return
match p with
| Under6 ?y => f"under six: %d" y
| Six => "six"
| Over6 ?z => f"over six: %d" z
endmatch
;
}
finally, there's partial matching. This makes use of opt so we can say
whether or not we actually matched the input:
union FourPattern
| Four
;
fun _pattern_FourPattern (x:int) =>
if x == 4 then Some Four else None[FourPattern
;
union FiveSixPattern
| Five
| Six
;
fun _pattern_FiveSixPattern (x:int) =>
if x == 5 then
Some $ Five
elif x == 6 then
Some $ Six
else
None
;
which can be used like this:
fun foo (x:int) =>
match x with
| Four => "four"
| Five => "five"
| Six => "six"
| _ => "other"
endmatch
;
which is just sugar for:
fun foo (x:int) = {
val p = if x == 4 then Some Four else None[FourPattern];
return
match p with
| Some Four => { "four" }
| None[FourPattern] = {
val p =
if x == 5 then
Some Five
elif x == 6 then
Some Six
else
None[FiveSixPattern]
;
return
match p with
| Some ?s =>
match
| Five => "five"
| Six => "six"
endmatch
| None[FiveSixPattern] => "other"
endmatch
;
}
endmatch ()
;
}
The nice thing with all of this is that we can create some very nice
sugar for a lot of libraries. For instance, we could have a really
simple interface to tre. I think it'd be really useful if we had
something like this in place.
-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys-and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
Felix-language mailing list
[EMAIL PROTECTED]
https://lists.sourceforge.net/lists/listinfo/felix-language