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

Reply via email to