1
votes

I am trying to write a generalised condition evaluator, similar to what the Lisp/Scheme people call cond, using quotations because they are the easiest way to get call-by-name semantics. I'm having trouble pattern-matching against the list cons operation, and can't seem to find out exactly how to represent it. Here's what I have so far:

open FSharp.Quotations.Evaluator
open Microsoft.FSharp.Quotations
open Microsoft.FSharp.Quotations.Patterns

let rec cond = function
  | NewUnionCase (Cons, [NewTuple [condition; value]; tail]) ->
    if QuotationEvaluator.Evaluate <| Expr.Cast(condition)
      then QuotationEvaluator.Evaluate <| Expr.Cast(value)
      else cond tail

  | _ -> raise <| MatchFailureException ("cond", 0, 0

The problem is with the Cons identifier in the first branch of the pattern match--it doesn't exist, and I can't figure out how to represent the list :: data constructor.

What is the correct way to pattern match against the list cons data constructor?

1
Why quotations? Why not functions? - Fyodor Soikin
And come to think of it, why implement such a thing at all? What's wrong with if - then - elif - else? - Fyodor Soikin
@FyodorSoikin, quotations (<@ ... @>) are faster to type than functions (fun () -> ...), and can be destructured and manipulated more easily. As to the overall justification, I'm trying to justify that we don't need new syntax for github.com/fsharp/fslang-suggestions/issues/519 - Yawar

1 Answers

2
votes

I don't think there is any easy way of writing Cons in the pattern directly, but you can use when clause to check whether the union case is a case named "Cons" of the list<T> type:

let rec cond = function
  | NewUnionCase (c, [NewTuple [condition; value]; tail]) 
      when c.Name = "Cons" && c.DeclaringType.IsGenericType &&
        c.DeclaringType.GetGenericTypeDefinition() = typedefof<_ list> -> 
      Some(condition, value, tail)
  | _ -> 
      None