You can use PowerPack Eval to evaluate only the arguments of a Call expression:
match e with | Call(_,mi,[arg1;arg2]) -> let arg1Value, arg2Value = arg1.Eval(), arg2.Eval() ...
And similarly for Lambda expressions, etc. Noticing this frees you from listing the permutations of Value , Property and other argument expressions.
Update
Since you want to avoid using Eval (not in vain if you are implementing a performance-oriented application), you will need to implement your own eval function using reflection (which still does not fade quickly, but should be faster than PowerPack Eval , which includes includes an intermediate translation of F # quotes into Linq expressions). You can start by maintaining a basic set of expressions and expanding from there as needed. Recursion is the key to help you get started:
open Microsoft.FSharp.Quotations open System.Reflection let rec eval expr = match expr with | Patterns.Value(value,_) -> value //value | Patterns.PropertyGet(Some(instance), pi, args) -> //instance property get pi.GetValue(eval instance, evalAll args) //notice recursive eval of instance expression and arg expressions | Patterns.PropertyGet(None, pi, args) -> //static property get pi.GetValue(null, evalAll args) | Patterns.Call(Some(instance), mi, args) -> //instance call mi.Invoke(eval instance, evalAll args) | Patterns.Call(None, mi, args) -> //static call mi.Invoke(null, evalAll args) | _ -> failwith "invalid expression" and evalAll exprs = exprs |> Seq.map eval |> Seq.toArray
And then wrapping this in the active template will improve the syntax:
let (|Eval|) expr = eval expr match e with | Patterns.Call(_, mi, [Eval(arg1Value); Eval(arg2Value)]) -> ...
Update 2
OK, this topic prompted me to try to implement a reliable reflection-based solution, and I did it with good results, which are now part of Unquote from version 2.0.0.
It turned out that it is not as complicated as I thought, at present I support all quotation expressions except AddressGet, AddressSet and NewDelegate. This is already better than PowerPack eval, which does not support PropertySet, VarSet, FieldSet, WhileLoop, ForIntegerRangeLoop and Quote, for example.
Some noteworthy implementation details relate to VarSet and VarGet, where I need to pass a list of environment / variable name lookups for each recursive call. This is a really great example of the beauty of functional programming with immutable data structures.
You should also pay special attention to the problems associated with exceptions: alternating TargetInvokationExceptions objects created by reflection when it catches exceptions coming from the methods it calls (this is very important for the TryWith evaluation to be correctly processed, as well as to improve the handling of custom exceptions that crash from the evaluation of quotes.
Perhaps the most โdifficultโ implementation detail or the most debilitating was the need to implement all the basic operators (well, as I could find: numeric and conversion operators, verified versions), since most of them are not given dynamic implementations in the F # library (they are implemented using static type tests without non-resident dynamic implementations), but also means a significant increase in performance when using these functions.
Some unofficial benchmarking. I am seeing a performance increase of up to 50 times compared to PowerPack (not precompiled) eval.
I am also sure that my reflection-based solution will be less error prone than PowerPack, simply because it is less complicated than the PowerPack approach (not to mention that I supported it with about 150 unit tests duly enhanced by Unquotes additional 200+ unit tests, which are now due to this implementation of eval).
If you want to look into the source code, the main modules are Evaluation.fs and DynamicOperators.fs (I blocked links in revision 257). Feel free to take and use the source code for your purposes, it is licensed under the Apache License 2.0! Or you can wait a week or so when I release Unquote 2.0.0, which will be published by rating operators and extensions.