From 259b4e2c2054f8e9e032ab82f85271bfc89fb93f Mon Sep 17 00:00:00 2001 From: Paul Westcott Date: Sat, 1 Nov 2014 06:47:34 +1100 Subject: [PATCH 01/26] Changed Let to use variable instead of Lambda Using Expression.Block to express let binding, which allowed support for VarSet. Needed to changed Patterns.Sequential to use Expression.Block as well. --- .../QuotationsEvaluator.fs | 22 +++++++++++-------- .../Tests.fs | 10 +++++++-- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fs b/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fs index 35a2c7e..c512be3 100644 --- a/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fs +++ b/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fs @@ -694,18 +694,22 @@ module QuotationEvaluationTypes = | Patterns.Sequential (e1,e2) -> let e1P = ConvExpr env e1 let e2P = ConvExpr env e2 - let minfo = match <@@ SequentialHelper @@> with Lambdas(_,Call(_,minfo,_)) -> minfo | _ -> failwith "couldn't find minfo" - let minfo = minfo.GetGenericMethodDefinition().MakeGenericMethod [| e1.Type; e2.Type |] - Expression.Call(minfo,[| e1P; e2P |]) |> asExpr + Expression.Block(e1P, e2P) |> asExpr | Patterns.Let (v,e,b) -> - let vP = ConvVar v - let envinner = { env with varEnv = Map.add v (vP |> asExpr) env.varEnv } - let bodyP = ConvExpr envinner b + let vP = Expression.Variable (v.Type, v.Name) let eP = ConvExpr env e - let ty = GetFuncType [| v.Type; b.Type |] - let lam = Expression.Lambda(ty,bodyP,[| vP |]) |> asExpr - Expression.Call(lam,ty.GetMethod("Invoke",instanceBindingFlags),[| eP |]) |> asExpr + let assign = Expression.Assign (vP, eP) |> asExpr + + let envInner = { env with varEnv = Map.add v (vP |> asExpr) env.varEnv } + let bodyP = ConvExpr envInner b + + Expression.Block ([vP], [assign; bodyP]) |> asExpr + + | Patterns.VarSet (variable, value) -> + let linqVariable = Map.find variable env.varEnv + let linqValue = ConvExpr env value + Expression.Assign (linqVariable, linqValue)|> asExpr | Patterns.Lambda(v,body) -> let vP = ConvVar v diff --git a/tests/FSharp.Quotations.Evaluator.Tests/Tests.fs b/tests/FSharp.Quotations.Evaluator.Tests/Tests.fs index d2869f0..2ba9d76 100644 --- a/tests/FSharp.Quotations.Evaluator.Tests/Tests.fs +++ b/tests/FSharp.Quotations.Evaluator.Tests/Tests.fs @@ -1225,8 +1225,14 @@ module QuotationCompilation = a := b + c + d + e ) @> check "qceva0" ((eval q) ()) () +[] +let MutableLetTests() = + let ml1 = + <@ let mutable x = 1 + x <- x + 1 + x @> - + checkEval "ml1" ml1 2 module CheckedTests = @@ -1367,4 +1373,4 @@ module CheckedTests = test "z7" (z7 = 2.0M) test "z10" (z10 = 1) - + \ No newline at end of file From 5005bebf15faeab3fc145f3ecf2a840c62cf7f8c Mon Sep 17 00:00:00 2001 From: Paul Westcott Date: Sat, 1 Nov 2014 13:16:40 +1100 Subject: [PATCH 02/26] Changed While loop to use Expression.Loop --- .../QuotationsEvaluator.fs | 27 ++++++++++--------- .../Tests.fs | 9 +++++++ 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fs b/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fs index c512be3..4f92143 100644 --- a/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fs +++ b/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fs @@ -60,10 +60,6 @@ module QuotationEvaluationTypes = let tyargs = typ.GetGenericArguments() tyargs.[0], tyargs.[1] - let WhileHelper gd b : 'T = - let rec loop () = if gd() then (b(); loop()) - loop(); - unbox (box ()) let ArrayAssignHelper (arr : 'T[]) (idx:int) (elem:'T) : 'unt = arr.[idx] <- elem; @@ -78,7 +74,6 @@ module QuotationEvaluationTypes = try e() with e when (filter e <> 0) -> handler e - let WhileMethod = match <@@ WhileHelper @@> with Lambdas(_,Call(_,minfo,_)) -> minfo | _ -> failwith "couldn't find minfo" let ArrayAssignMethod = match <@@ ArrayAssignHelper @@> with Lambdas(_,Call(_,minfo,_)) -> minfo | _ -> failwith "couldn't find minfo" let TryFinallyMethod = match <@@ TryFinallyHelper @@> with Lambdas(_,Call(_,minfo,_)) -> minfo | _ -> failwith "couldn't find minfo" let TryWithMethod = match <@@ TryWithHelper @@> with Lambdas(_,Call(_,minfo,_)) -> minfo | _ -> failwith "couldn't find minfo" @@ -340,8 +335,6 @@ module QuotationEvaluationTypes = let IsVoidType (ty:System.Type) = (ty = typeof) - let SequentialHelper (x:'T) (y:'U) = y - let LinqExpressionHelper (x:'T) : Expression<'T> = failwith "" let MakeFakeExpression (x:Expr) = @@ -720,11 +713,21 @@ module QuotationEvaluationTypes = let convDelegate = Expression.Lambda(convType, bodyP, [| vP |]) |> asExpr Expression.Call(typeof,"ToFSharpFunc",tyargs,[| convDelegate |]) |> asExpr - | Patterns.WhileLoop(gd,b) -> - let gdP = ConvExpr env <@@ (fun () -> (%%gd:bool)) @@> - let bP = ConvExpr env <@@ (fun () -> (%%b:unit)) @@> - let minfo = WhileMethod.GetGenericMethodDefinition().MakeGenericMethod [| typeof |] - Expression.Call(minfo,[| gdP; bP |]) |> asExpr + | Patterns.WhileLoop(condition, iteration) -> + let linqCondition = ConvExpr env condition + let linqIteration = ConvExpr env iteration + + let breakLabel = Expression.Label () + let linqLoop = + Expression.Loop ( + Expression.Block ( + Expression.IfThenElse ( + linqCondition, + linqIteration, + Expression.Break breakLabel)), + breakLabel) + + linqLoop |> asExpr | Patterns.TryFinally(e,h) -> let eP = ConvExpr env (Expr.Lambda(new Var("unitVar",typeof), e)) diff --git a/tests/FSharp.Quotations.Evaluator.Tests/Tests.fs b/tests/FSharp.Quotations.Evaluator.Tests/Tests.fs index 2ba9d76..3be5763 100644 --- a/tests/FSharp.Quotations.Evaluator.Tests/Tests.fs +++ b/tests/FSharp.Quotations.Evaluator.Tests/Tests.fs @@ -1234,6 +1234,15 @@ let MutableLetTests() = checkEval "ml1" ml1 2 +[] +let WhileLoopTests() = + let wl1 = + <@ let mutable x = 1 + while x < 10 do + x <- x + 1 + x @> + + checkEval "ml1" wl1 10 module CheckedTests = open Microsoft.FSharp.Core.Operators.Checked From aec08a8b0c819081dfa7ef878d0f1bc365df5127 Mon Sep 17 00:00:00 2001 From: Paul Westcott Date: Sat, 1 Nov 2014 14:07:27 +1100 Subject: [PATCH 03/26] Fix; while loop type was wrong for delegate Not sure if this is the greatest solution; but works. --- src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fs b/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fs index 4f92143..28dd1d2 100644 --- a/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fs +++ b/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fs @@ -667,7 +667,13 @@ module QuotationEvaluationTypes = | Patterns.NewDelegate(dty,vs,b) -> let vsP = List.map ConvVar vs let env = {env with varEnv = List.foldBack2 (fun (v:Var) vP -> Map.add v (vP |> asExpr)) vs vsP env.varEnv } - let bodyP = ConvExpr env b + let bodyP = ConvExpr env b + + let bodyP = + if IsVoidType bodyP.Type + then Expression.Block(bodyP, ConvExpr env <@ () @>) |> asExpr + else bodyP + Expression.Lambda(dty, bodyP, vsP) |> asExpr | Patterns.NewTuple(args) -> From 55752b42da7b812849b596d668734fdf94441fef Mon Sep 17 00:00:00 2001 From: Paul Westcott Date: Sat, 1 Nov 2014 14:44:06 +1100 Subject: [PATCH 04/26] Implemented Patterns.ForIntegerRangeLoop --- .../QuotationsEvaluator.fs | 32 +++++++++++++++++++ .../Tests.fs | 10 ++++++ 2 files changed, 42 insertions(+) diff --git a/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fs b/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fs index 28dd1d2..f20bda5 100644 --- a/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fs +++ b/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fs @@ -734,6 +734,38 @@ module QuotationEvaluationTypes = breakLabel) linqLoop |> asExpr + + | Patterns.ForIntegerRangeLoop(indexer, lowerValue, upperValue, iteration) -> + let linqLowerValue = ConvExpr env lowerValue + let linqUpperValue = ConvExpr env upperValue + let linqIndexer = Expression.Variable (linqLowerValue.Type, indexer.Name) + let linqAssignLower = Expression.Assign (linqIndexer, linqLowerValue) + let linqCondition = Expression.LessThanOrEqual (linqIndexer, linqUpperValue) + + let envInner = { env with varEnv = Map.add indexer (linqIndexer |> asExpr) env.varEnv } + + let linqIteration = + Expression.Block ( + ConvExpr envInner iteration, + Expression.Assign(linqIndexer, Expression.Increment (linqIndexer))) + + let breakLabel = Expression.Label () + let linqLoop = + Expression.Loop ( + Expression.Block ( + Expression.IfThenElse ( + linqCondition, + linqIteration, + Expression.Break breakLabel)), + breakLabel) + + let linqStatements = + Expression.Block ( + [linqIndexer], + [linqAssignLower |> asExpr; linqLoop |> asExpr] + ) + + linqStatements |> asExpr | Patterns.TryFinally(e,h) -> let eP = ConvExpr env (Expr.Lambda(new Var("unitVar",typeof), e)) diff --git a/tests/FSharp.Quotations.Evaluator.Tests/Tests.fs b/tests/FSharp.Quotations.Evaluator.Tests/Tests.fs index 3be5763..eda04ae 100644 --- a/tests/FSharp.Quotations.Evaluator.Tests/Tests.fs +++ b/tests/FSharp.Quotations.Evaluator.Tests/Tests.fs @@ -1244,6 +1244,16 @@ let WhileLoopTests() = checkEval "ml1" wl1 10 +[] +let ForLoopTests() = + let fl1 = + <@ let mutable x = 0 + for i = 0 to 10 do + x <- x + i + x @> + + checkEval "fl1" fl1 (Seq.sum [0..10]) + module CheckedTests = open Microsoft.FSharp.Core.Operators.Checked From 9b19dd0499e6446e5761db169e1ab4f864118063 Mon Sep 17 00:00:00 2001 From: Paul Westcott Date: Sat, 1 Nov 2014 19:26:12 +1100 Subject: [PATCH 05/26] Moved the "Fix" of wrong delegate type The While loop code was called from other places, so moved the addition of the Unit type up to there. --- .../QuotationsEvaluator.fs | 11 ++++------- tests/FSharp.Quotations.Evaluator.Tests/Tests.fs | 8 ++++++++ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fs b/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fs index f20bda5..1075e52 100644 --- a/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fs +++ b/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fs @@ -668,12 +668,6 @@ module QuotationEvaluationTypes = let vsP = List.map ConvVar vs let env = {env with varEnv = List.foldBack2 (fun (v:Var) vP -> Map.add v (vP |> asExpr)) vs vsP env.varEnv } let bodyP = ConvExpr env b - - let bodyP = - if IsVoidType bodyP.Type - then Expression.Block(bodyP, ConvExpr env <@ () @>) |> asExpr - else bodyP - Expression.Lambda(dty, bodyP, vsP) |> asExpr | Patterns.NewTuple(args) -> @@ -732,8 +726,11 @@ module QuotationEvaluationTypes = linqIteration, Expression.Break breakLabel)), breakLabel) + + let linqAsUnitType = + Expression.Block(linqLoop, ConvExpr env <@ () @>) - linqLoop |> asExpr + linqAsUnitType |> asExpr | Patterns.ForIntegerRangeLoop(indexer, lowerValue, upperValue, iteration) -> let linqLowerValue = ConvExpr env lowerValue diff --git a/tests/FSharp.Quotations.Evaluator.Tests/Tests.fs b/tests/FSharp.Quotations.Evaluator.Tests/Tests.fs index eda04ae..cafe30f 100644 --- a/tests/FSharp.Quotations.Evaluator.Tests/Tests.fs +++ b/tests/FSharp.Quotations.Evaluator.Tests/Tests.fs @@ -1253,6 +1253,14 @@ let ForLoopTests() = x @> checkEval "fl1" fl1 (Seq.sum [0..10]) + + let fl2 = + <@ let mutable x = 0 + for i in [0..10] do + x <- x + i + x @> + + checkEval "fl2" fl2 (Seq.sum [0..10]) module CheckedTests = open Microsoft.FSharp.Core.Operators.Checked From bf8a1bdb7b7157352d53baaa3cd11a39bd5f724f Mon Sep 17 00:00:00 2001 From: Paul Westcott Date: Sat, 1 Nov 2014 19:50:47 +1100 Subject: [PATCH 06/26] Remove unnecessary ActionHelper/FuncHelpers Documentation for Expression.GetActionType and Expression.GetFuncType say they support arrays up to 16 & 17 respectively; so removed helpers that duplicated such functionality. --- .../QuotationsEvaluator.fs | 120 ++++++------------ .../QuotationsEvaluator.fsi | 48 ------- 2 files changed, 36 insertions(+), 132 deletions(-) diff --git a/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fs b/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fs index 1075e52..40bfd63 100644 --- a/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fs +++ b/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fs @@ -79,35 +79,11 @@ module QuotationEvaluationTypes = let TryWithMethod = match <@@ TryWithHelper @@> with Lambdas(_,Call(_,minfo,_)) -> minfo | _ -> failwith "couldn't find minfo" module HelperTypes = - type ActionHelper<'T1,'T2,'T3,'T4,'T5> = delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 -> unit - type ActionHelper<'T1,'T2,'T3,'T4,'T5,'T6> = delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 -> unit - type ActionHelper<'T1,'T2,'T3,'T4,'T5,'T6,'T7> = delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 -> unit - type ActionHelper<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8> = delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 -> unit - type ActionHelper<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8,'T9> = delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 * 'T9 -> unit - type ActionHelper<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8,'T9,'T10> = delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 * 'T9 * 'T10 -> unit - type ActionHelper<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8,'T9,'T10, 'T11> = delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 * 'T9 * 'T10 * 'T11 -> unit - type ActionHelper<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8,'T9,'T10, 'T11, 'T12> = delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 * 'T9 * 'T10 * 'T11 * 'T12 -> unit - type ActionHelper<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8,'T9,'T10, 'T11, 'T12, 'T13> = delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 * 'T9 * 'T10 * 'T11 * 'T12 * 'T13 -> unit - type ActionHelper<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8,'T9,'T10, 'T11, 'T12, 'T13, 'T14> = delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 * 'T9 * 'T10 * 'T11 * 'T12 * 'T13 * 'T14 -> unit - type ActionHelper<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8,'T9,'T10, 'T11, 'T12, 'T13, 'T14, 'T15> = delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 * 'T9 * 'T10 * 'T11 * 'T12 * 'T13 * 'T14 * 'T15 -> unit - type ActionHelper<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8,'T9,'T10, 'T11, 'T12, 'T13, 'T14, 'T15, 'T16> = delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 * 'T9 * 'T10 * 'T11 * 'T12 * 'T13 * 'T14 * 'T15 * 'T16 -> unit type ActionHelper<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8,'T9,'T10, 'T11, 'T12, 'T13, 'T14, 'T15, 'T16, 'T17> = delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 * 'T9 * 'T10 * 'T11 * 'T12 * 'T13 * 'T14 * 'T15 * 'T16 * 'T17 -> unit type ActionHelper<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8,'T9,'T10, 'T11, 'T12, 'T13, 'T14, 'T15, 'T16, 'T17, 'T18> = delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 * 'T9 * 'T10 * 'T11 * 'T12 * 'T13 * 'T14 * 'T15 * 'T16 * 'T17 * 'T18 -> unit type ActionHelper<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8,'T9,'T10, 'T11, 'T12, 'T13, 'T14, 'T15, 'T16, 'T17, 'T18, 'T19> = delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 * 'T9 * 'T10 * 'T11 * 'T12 * 'T13 * 'T14 * 'T15 * 'T16 * 'T17 * 'T18 * 'T19 -> unit type ActionHelper<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8,'T9,'T10, 'T11, 'T12, 'T13, 'T14, 'T15, 'T16, 'T17, 'T18, 'T19, 'T20> = delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 * 'T9 * 'T10 * 'T11 * 'T12 * 'T13 * 'T14 * 'T15 * 'T16 * 'T17 * 'T18 * 'T19 * 'T20 -> unit - type FuncHelper<'T1,'T2,'T3,'T4,'T5,'T6> = delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 -> 'T6 - type FuncHelper<'T1,'T2,'T3,'T4,'T5,'T6,'T7> = delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 -> 'T7 - type FuncHelper<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8> = delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 -> 'T8 - type FuncHelper<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8,'T9> = delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 -> 'T9 - type FuncHelper<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8,'T9,'T10> = delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 * 'T9 -> 'T10 - type FuncHelper<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8,'T9,'T10, 'T11> = delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 * 'T9 * 'T10 -> 'T11 - type FuncHelper<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8,'T9,'T10, 'T11, 'T12> = delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 * 'T9 * 'T10 * 'T11 -> 'T12 - type FuncHelper<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8,'T9,'T10, 'T11, 'T12, 'T13> = delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 * 'T9 * 'T10 * 'T11 * 'T12 -> 'T13 - type FuncHelper<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8,'T9,'T10, 'T11, 'T12, 'T13, 'T14> = delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 * 'T9 * 'T10 * 'T11 * 'T12 * 'T13 -> 'T14 - type FuncHelper<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8,'T9,'T10, 'T11, 'T12, 'T13, 'T14, 'T15> = delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 * 'T9 * 'T10 * 'T11 * 'T12 * 'T13 * 'T14 -> 'T15 - type FuncHelper<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8,'T9,'T10, 'T11, 'T12, 'T13, 'T14, 'T15, 'T16> = delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 * 'T9 * 'T10 * 'T11 * 'T12 * 'T13 * 'T14 * 'T15 -> 'T16 - type FuncHelper<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8,'T9,'T10, 'T11, 'T12, 'T13, 'T14, 'T15, 'T16, 'T17> = delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 * 'T9 * 'T10 * 'T11 * 'T12 * 'T13 * 'T14 * 'T15 * 'T16 -> 'T17 type FuncHelper<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8,'T9,'T10, 'T11, 'T12, 'T13, 'T14, 'T15, 'T16, 'T17, 'T18> = delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 * 'T9 * 'T10 * 'T11 * 'T12 * 'T13 * 'T14 * 'T15 * 'T16 * 'T17 -> 'T18 type FuncHelper<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8,'T9,'T10, 'T11, 'T12, 'T13, 'T14, 'T15, 'T16, 'T17, 'T18, 'T19> = delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 * 'T9 * 'T10 * 'T11 * 'T12 * 'T13 * 'T14 * 'T15 * 'T16 * 'T17 * 'T18 -> 'T19 type FuncHelper<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8,'T9,'T10, 'T11, 'T12, 'T13, 'T14, 'T15, 'T16, 'T17, 'T18, 'T19, 'T20> = delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 * 'T9 * 'T10 * 'T11 * 'T12 * 'T13 * 'T14 * 'T15 * 'T16 * 'T17 * 'T18 * 'T19 -> 'T20 @@ -116,22 +92,10 @@ module QuotationEvaluationTypes = open HelperTypes let GetActionType (args:Type[]) = - if args.Length <= 4 then + if args.Length <= 16 then Expression.GetActionType args else match args.Length with - | 5 -> typedefof>.MakeGenericType args - | 6 -> typedefof>.MakeGenericType args - | 7 -> typedefof>.MakeGenericType args - | 8 -> typedefof>.MakeGenericType args - | 9 -> typedefof>.MakeGenericType args - | 10 -> typedefof>.MakeGenericType args - | 11 -> typedefof>.MakeGenericType args - | 12 -> typedefof>.MakeGenericType args - | 13 -> typedefof>.MakeGenericType args - | 14 -> typedefof>.MakeGenericType args - | 15 -> typedefof>.MakeGenericType args - | 16 -> typedefof>.MakeGenericType args | 17 -> typedefof>.MakeGenericType args | 18 -> typedefof>.MakeGenericType args | 19 -> typedefof>.MakeGenericType args @@ -139,22 +103,10 @@ module QuotationEvaluationTypes = | _ -> raise <| new NotSupportedException("Quotation expressions with statements or closures containing more then 20 free variables may not be translated in this release of the F# PowerPack. This is due to limitations in the variable binding expression forms available in LINQ expression trees") let GetFuncType (args:Type[]) = - if args.Length <= 5 then + if args.Length <= 17 then Expression.GetFuncType args else match args.Length with - | 6 -> typedefof>.MakeGenericType args - | 7 -> typedefof>.MakeGenericType args - | 8 -> typedefof>.MakeGenericType args - | 9 -> typedefof>.MakeGenericType args - | 10 -> typedefof>.MakeGenericType args - | 11 -> typedefof>.MakeGenericType args - | 12 -> typedefof>.MakeGenericType args - | 13 -> typedefof>.MakeGenericType args - | 14 -> typedefof>.MakeGenericType args - | 15 -> typedefof>.MakeGenericType args - | 16 -> typedefof>.MakeGenericType args - | 17 -> typedefof>.MakeGenericType args | 18 -> typedefof>.MakeGenericType args | 19 -> typedefof>.MakeGenericType args | 20 -> typedefof>.MakeGenericType args @@ -190,10 +142,10 @@ module QuotationEvaluationTypes = B.Invoke(f1,f2,f3) let LetRec4Helper - (F1:FuncHelper<_,_,_,_,_,_>) - (F2:FuncHelper<_,_,_,_,_,_>) - (F3:FuncHelper<_,_,_,_,_,_>) - (F4:FuncHelper<_,_,_,_,_,_>) + (F1:System.Func<_,_,_,_,_,_>) + (F2:System.Func<_,_,_,_,_,_>) + (F3:System.Func<_,_,_,_,_,_>) + (F4:System.Func<_,_,_,_,_,_>) (B:System.Func<_,_,_,_,_>) = let f1hole = ref (Unchecked.defaultof<_>) let f2hole = ref (Unchecked.defaultof<_>) @@ -211,12 +163,12 @@ module QuotationEvaluationTypes = let LetRec5Helper - (F1:FuncHelper<_,_,_,_,_,_,_>) - (F2:FuncHelper<_,_,_,_,_,_,_>) - (F3:FuncHelper<_,_,_,_,_,_,_>) - (F4:FuncHelper<_,_,_,_,_,_,_>) - (F5:FuncHelper<_,_,_,_,_,_,_>) - (B:FuncHelper<_,_,_,_,_,_>) = + (F1:System.Func<_,_,_,_,_,_,_>) + (F2:System.Func<_,_,_,_,_,_,_>) + (F3:System.Func<_,_,_,_,_,_,_>) + (F4:System.Func<_,_,_,_,_,_,_>) + (F5:System.Func<_,_,_,_,_,_,_>) + (B:System.Func<_,_,_,_,_,_>) = let f1hole = ref (Unchecked.defaultof<_>) let f2hole = ref (Unchecked.defaultof<_>) let f3hole = ref (Unchecked.defaultof<_>) @@ -235,13 +187,13 @@ module QuotationEvaluationTypes = B.Invoke(f1,f2,f3,f4,f5) let LetRec6Helper - (F1:FuncHelper<_,_,_,_,_,_,_,_>) - (F2:FuncHelper<_,_,_,_,_,_,_,_>) - (F3:FuncHelper<_,_,_,_,_,_,_,_>) - (F4:FuncHelper<_,_,_,_,_,_,_,_>) - (F5:FuncHelper<_,_,_,_,_,_,_,_>) - (F6:FuncHelper<_,_,_,_,_,_,_,_>) - (B:FuncHelper<_,_,_,_,_,_,_>) = + (F1:System.Func<_,_,_,_,_,_,_,_>) + (F2:System.Func<_,_,_,_,_,_,_,_>) + (F3:System.Func<_,_,_,_,_,_,_,_>) + (F4:System.Func<_,_,_,_,_,_,_,_>) + (F5:System.Func<_,_,_,_,_,_,_,_>) + (F6:System.Func<_,_,_,_,_,_,_,_>) + (B:System.Func<_,_,_,_,_,_,_>) = let f1hole = ref (Unchecked.defaultof<_>) let f2hole = ref (Unchecked.defaultof<_>) let f3hole = ref (Unchecked.defaultof<_>) @@ -264,14 +216,14 @@ module QuotationEvaluationTypes = let LetRec7Helper - (F1:FuncHelper<_,_,_,_,_,_,_,_,_>) - (F2:FuncHelper<_,_,_,_,_,_,_,_,_>) - (F3:FuncHelper<_,_,_,_,_,_,_,_,_>) - (F4:FuncHelper<_,_,_,_,_,_,_,_,_>) - (F5:FuncHelper<_,_,_,_,_,_,_,_,_>) - (F6:FuncHelper<_,_,_,_,_,_,_,_,_>) - (F7:FuncHelper<_,_,_,_,_,_,_,_,_>) - (B:FuncHelper<_,_,_,_,_,_,_,_>) = + (F1:System.Func<_,_,_,_,_,_,_,_,_>) + (F2:System.Func<_,_,_,_,_,_,_,_,_>) + (F3:System.Func<_,_,_,_,_,_,_,_,_>) + (F4:System.Func<_,_,_,_,_,_,_,_,_>) + (F5:System.Func<_,_,_,_,_,_,_,_,_>) + (F6:System.Func<_,_,_,_,_,_,_,_,_>) + (F7:System.Func<_,_,_,_,_,_,_,_,_>) + (B:System.Func<_,_,_,_,_,_,_,_>) = let f1hole = ref (Unchecked.defaultof<_>) let f2hole = ref (Unchecked.defaultof<_>) let f3hole = ref (Unchecked.defaultof<_>) @@ -297,15 +249,15 @@ module QuotationEvaluationTypes = let LetRec8Helper - (F1:FuncHelper<_,_,_,_,_,_,_,_,_,_>) - (F2:FuncHelper<_,_,_,_,_,_,_,_,_,_>) - (F3:FuncHelper<_,_,_,_,_,_,_,_,_,_>) - (F4:FuncHelper<_,_,_,_,_,_,_,_,_,_>) - (F5:FuncHelper<_,_,_,_,_,_,_,_,_,_>) - (F6:FuncHelper<_,_,_,_,_,_,_,_,_,_>) - (F7:FuncHelper<_,_,_,_,_,_,_,_,_,_>) - (F8:FuncHelper<_,_,_,_,_,_,_,_,_,_>) - (B:FuncHelper<_,_,_,_,_,_,_,_,_>) = + (F1:System.Func<_,_,_,_,_,_,_,_,_,_>) + (F2:System.Func<_,_,_,_,_,_,_,_,_,_>) + (F3:System.Func<_,_,_,_,_,_,_,_,_,_>) + (F4:System.Func<_,_,_,_,_,_,_,_,_,_>) + (F5:System.Func<_,_,_,_,_,_,_,_,_,_>) + (F6:System.Func<_,_,_,_,_,_,_,_,_,_>) + (F7:System.Func<_,_,_,_,_,_,_,_,_,_>) + (F8:System.Func<_,_,_,_,_,_,_,_,_,_>) + (B:System.Func<_,_,_,_,_,_,_,_,_>) = let f1hole = ref (Unchecked.defaultof<_>) let f2hole = ref (Unchecked.defaultof<_>) let f3hole = ref (Unchecked.defaultof<_>) diff --git a/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fsi b/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fsi index 54b9881..7b38754 100644 --- a/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fsi +++ b/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fsi @@ -105,30 +105,6 @@ namespace FSharp.Quotations.Evaluator /// A set of types used for implementing quotation conversions. /// These are public only because targets of Linq Lambda expressions require them to be so module HelperTypes = - [] - type ActionHelper<'T1,'T2,'T3,'T4,'T5> = delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 -> unit - [] - type ActionHelper<'T1,'T2,'T3,'T4,'T5,'T6> = delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 -> unit - [] - type ActionHelper<'T1,'T2,'T3,'T4,'T5,'T6,'T7> = delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 -> unit - [] - type ActionHelper<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8> = delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 -> unit - [] - type ActionHelper<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8,'T9> = delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 * 'T9 -> unit - [] - type ActionHelper<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8,'T9,'T10> = delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 * 'T9 * 'T10 -> unit - [] - type ActionHelper<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8,'T9,'T10, 'T11> = delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 * 'T9 * 'T10 * 'T11 -> unit - [] - type ActionHelper<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8,'T9,'T10, 'T11, 'T12> = delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 * 'T9 * 'T10 * 'T11 * 'T12 -> unit - [] - type ActionHelper<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8,'T9,'T10, 'T11, 'T12, 'T13> = delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 * 'T9 * 'T10 * 'T11 * 'T12 * 'T13 -> unit - [] - type ActionHelper<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8,'T9,'T10, 'T11, 'T12, 'T13, 'T14> = delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 * 'T9 * 'T10 * 'T11 * 'T12 * 'T13 * 'T14 -> unit - [] - type ActionHelper<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8,'T9,'T10, 'T11, 'T12, 'T13, 'T14, 'T15> = delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 * 'T9 * 'T10 * 'T11 * 'T12 * 'T13 * 'T14 * 'T15 -> unit - [] - type ActionHelper<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8,'T9,'T10, 'T11, 'T12, 'T13, 'T14, 'T15, 'T16> = delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 * 'T9 * 'T10 * 'T11 * 'T12 * 'T13 * 'T14 * 'T15 * 'T16 -> unit [] type ActionHelper<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8,'T9,'T10, 'T11, 'T12, 'T13, 'T14, 'T15, 'T16, 'T17> = delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 * 'T9 * 'T10 * 'T11 * 'T12 * 'T13 * 'T14 * 'T15 * 'T16 * 'T17 -> unit [] @@ -138,30 +114,6 @@ namespace FSharp.Quotations.Evaluator [] type ActionHelper<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8,'T9,'T10, 'T11, 'T12, 'T13, 'T14, 'T15, 'T16, 'T17, 'T18, 'T19, 'T20> = delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 * 'T9 * 'T10 * 'T11 * 'T12 * 'T13 * 'T14 * 'T15 * 'T16 * 'T17 * 'T18 * 'T19 * 'T20 -> unit - [] - type FuncHelper<'T1,'T2,'T3,'T4,'T5,'T6> = delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 -> 'T6 - [] - type FuncHelper<'T1,'T2,'T3,'T4,'T5,'T6,'T7> = delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 -> 'T7 - [] - type FuncHelper<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8> = delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 -> 'T8 - [] - type FuncHelper<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8,'T9> = delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 -> 'T9 - [] - type FuncHelper<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8,'T9,'T10> = delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 * 'T9 -> 'T10 - [] - type FuncHelper<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8,'T9,'T10, 'T11> = delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 * 'T9 * 'T10 -> 'T11 - [] - type FuncHelper<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8,'T9,'T10, 'T11, 'T12> = delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 * 'T9 * 'T10 * 'T11 -> 'T12 - [] - type FuncHelper<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8,'T9,'T10, 'T11, 'T12, 'T13> = delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 * 'T9 * 'T10 * 'T11 * 'T12 -> 'T13 - [] - type FuncHelper<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8,'T9,'T10, 'T11, 'T12, 'T13, 'T14> = delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 * 'T9 * 'T10 * 'T11 * 'T12 * 'T13 -> 'T14 - [] - type FuncHelper<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8,'T9,'T10, 'T11, 'T12, 'T13, 'T14, 'T15> = delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 * 'T9 * 'T10 * 'T11 * 'T12 * 'T13 * 'T14 -> 'T15 - [] - type FuncHelper<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8,'T9,'T10, 'T11, 'T12, 'T13, 'T14, 'T15, 'T16> = delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 * 'T9 * 'T10 * 'T11 * 'T12 * 'T13 * 'T14 * 'T15 -> 'T16 - [] - type FuncHelper<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8,'T9,'T10, 'T11, 'T12, 'T13, 'T14, 'T15, 'T16, 'T17> = delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 * 'T9 * 'T10 * 'T11 * 'T12 * 'T13 * 'T14 * 'T15 * 'T16 -> 'T17 [] type FuncHelper<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8,'T9,'T10, 'T11, 'T12, 'T13, 'T14, 'T15, 'T16, 'T17, 'T18> = delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 * 'T9 * 'T10 * 'T11 * 'T12 * 'T13 * 'T14 * 'T15 * 'T16 * 'T17 -> 'T18 [] From b876d8cadf90b8c2c80e2f52f8c144a56feb494c Mon Sep 17 00:00:00 2001 From: "F# Software Foundation (Git Repo Management)" Date: Sat, 1 Nov 2014 19:46:57 +0000 Subject: [PATCH 07/26] pdate build script --- build.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 build.sh diff --git a/build.sh b/build.sh old mode 100644 new mode 100755 From 6cecc503b9bfc8886e86abd02f5727d495ee7e98 Mon Sep 17 00:00:00 2001 From: "F# Software Foundation (Git Repo Management)" Date: Sat, 1 Nov 2014 23:31:38 +0000 Subject: [PATCH 08/26] Bump version to 1.0.2 --- RELEASE_NOTES.md | 3 +++ src/FSharp.Quotations.Evaluator/AssemblyInfo.fs | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 457d5e1..0587530 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -4,3 +4,6 @@ ### 1.0.1 - Update release * Updated release notes + +### 1.0.2 - Using System.Linq.Expressions .net 4.0+ functionality +* Updated release notes diff --git a/src/FSharp.Quotations.Evaluator/AssemblyInfo.fs b/src/FSharp.Quotations.Evaluator/AssemblyInfo.fs index 25e72a8..a3a9ff3 100644 --- a/src/FSharp.Quotations.Evaluator/AssemblyInfo.fs +++ b/src/FSharp.Quotations.Evaluator/AssemblyInfo.fs @@ -4,9 +4,9 @@ open System.Reflection [] [] [] -[] -[] +[] +[] do () module internal AssemblyVersionInformation = - let [] Version = "1.0.1" + let [] Version = "1.0.2" From fed0a1bc667db28f5431990dbcc76fccd125935c Mon Sep 17 00:00:00 2001 From: Sergey Tihon Date: Sun, 2 Nov 2014 09:39:02 +0300 Subject: [PATCH 09/26] Logo added --- docs/files/img/logo-template.pdn | Bin 16947 -> 0 bytes docs/files/img/logo.pdn | Bin 0 -> 17866 bytes docs/files/img/logo.png | Bin 29944 -> 3593 bytes nuget/FSharp.Quotations.Evaluator.nuspec | 4 ++-- 4 files changed, 2 insertions(+), 2 deletions(-) delete mode 100644 docs/files/img/logo-template.pdn create mode 100644 docs/files/img/logo.pdn diff --git a/docs/files/img/logo-template.pdn b/docs/files/img/logo-template.pdn deleted file mode 100644 index 3a742ad32a2044e4b1b876e6caed1417a7122f03..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16947 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 USpQqaS?+2#)mwi-#Zd6S0b>{`G5`Po diff --git a/docs/files/img/logo.pdn b/docs/files/img/logo.pdn new file mode 100644 index 0000000000000000000000000000000000000000..e9b9cec8a86bdbb1c874f97d2164cb4c44fcd8e4 GIT binary patch literal 17866 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 literal 29944 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 http://github.com/fsprojects/FSharp.Quotations.Evaluator/blob/master/LICENSE.txt http://fsprojects.github.com/FSharp.Quotations.Evaluator - https://raw.github.com/fsharp/FSharp.Quotations.Evaluator/master/nuget/logo.png + https://raw.githubusercontent.com/fsprojects/FSharp.Quotations.Evaluator/master/docs/files/img/logo.png false @summary@ @description@ @releaseNotes@ - Copyright 2013 + Copyright 2014 @tags@ From 6983d3e96ccfe372f60a0c1f82d9b990a17cd1ce Mon Sep 17 00:00:00 2001 From: Paul Westcott Date: Mon, 3 Nov 2014 20:59:18 +1100 Subject: [PATCH 10/26] Basis of test suite framework Taking samples from [rosettacode](http://rosettacode.org/) --- .../FSharp.Quotations.Evaluator.Tests.fsproj | 5 +- .../Rosetta.fs | 70 +++++++++++++++++++ 2 files changed, 73 insertions(+), 2 deletions(-) create mode 100644 tests/FSharp.Quotations.Evaluator.Tests/Rosetta.fs diff --git a/tests/FSharp.Quotations.Evaluator.Tests/FSharp.Quotations.Evaluator.Tests.fsproj b/tests/FSharp.Quotations.Evaluator.Tests/FSharp.Quotations.Evaluator.Tests.fsproj index c541a7b..73ba2a9 100644 --- a/tests/FSharp.Quotations.Evaluator.Tests/FSharp.Quotations.Evaluator.Tests.fsproj +++ b/tests/FSharp.Quotations.Evaluator.Tests/FSharp.Quotations.Evaluator.Tests.fsproj @@ -1,4 +1,4 @@ - + @@ -59,6 +59,7 @@ + @@ -88,4 +89,4 @@ --> - + \ No newline at end of file diff --git a/tests/FSharp.Quotations.Evaluator.Tests/Rosetta.fs b/tests/FSharp.Quotations.Evaluator.Tests/Rosetta.fs new file mode 100644 index 0000000..bc5b697 --- /dev/null +++ b/tests/FSharp.Quotations.Evaluator.Tests/Rosetta.fs @@ -0,0 +1,70 @@ +module FSharp.Quotations.Evaluator.Rosetta + +open System +open NUnit.Framework +open Microsoft.FSharp.Quotations +open FSharp.Quotations.Evaluator.Unittests + +open Microsoft.FSharp.Quotations + +// [Expanding quotations](http://fssnip.net/bx) +let expand (expr:Expr<'a>) : Expr<'a>= + /// The parameter 'vars' is an immutable map that assigns expressions to variables + /// (as we recursively process the tree, we replace all known variables) + let rec expand vars expr = + // First recursively process & replace variables + let expanded = + match expr with + // If the variable has an assignment, then replace it with the expression + | ExprShape.ShapeVar v when Map.containsKey v vars -> vars.[v] + // Apply 'expand' recursively on all sub-expressions + | ExprShape.ShapeVar v -> Expr.Var v + | Patterns.Call(body, DerivedPatterns.MethodWithReflectedDefinition meth, args) -> + let this = match body with Some b -> Expr.Application(meth, b) | _ -> meth + let res = Expr.Applications(this, [ for a in args -> [a]]) + expand vars res + | ExprShape.ShapeLambda(v, expr) -> + Expr.Lambda(v, expand vars expr) + | ExprShape.ShapeCombination(o, exprs) -> + ExprShape.RebuildShapeCombination(o, List.map (expand vars) exprs) + + // After expanding, try reducing the expression - we can replace 'let' + // expressions and applications where the first argument is lambda + match expanded with + | Patterns.Application(ExprShape.ShapeLambda(v, body), assign) + | Patterns.Let(v, assign, body) -> + expand (Map.add v (expand vars assign) vars) body + | _ -> expanded + + match expand Map.empty expr with + | Patterns.Lambda(v,body) -> Expr.Cast body + | _ -> failwith "Unexpected Form" + +[] +let ``[answerDoors](http://rosettacode.org/wiki/100_doors#F.23)`` () = + let ToggleNth n (lst:bool array) = // Toggle every n'th door + [(n-1) .. n .. 99] // For each appropriate door + |> Seq.iter (fun i -> lst.[i] <- not lst.[i]) // toggle it + let doors = Array.create 100 false // Initialize all doors to closed + Seq.iter (fun n -> ToggleNth n doors) [1..100] // toggle the appropriate doors for each pass + doors + +[] +let ``[answer2](http://rosettacode.org/wiki/100_doors#F.23)`` () = + let PerfectSquare n = + let sqrt = int(Math.Sqrt(float n)) + n = sqrt * sqrt + [| for i in 1..100 do yield PerfectSquare i |] + +[] +let ``http://rosettacode.org/wiki/100_doors#F.23`` () = + let quotation = expand <@ ``[answerDoors](http://rosettacode.org/wiki/100_doors#F.23)`` () @> + let result = ``[answerDoors](http://rosettacode.org/wiki/100_doors#F.23)`` () + + checkEval "1" quotation result + + let quotation = expand <@ ``[answer2](http://rosettacode.org/wiki/100_doors#F.23)`` () @> + let result = ``[answer2](http://rosettacode.org/wiki/100_doors#F.23)`` () + + checkEval "2" quotation result + From bc607e98c460637da30d42e0c0b91ebe55efc9df Mon Sep 17 00:00:00 2001 From: Paul Westcott Date: Tue, 4 Nov 2014 15:13:56 +1100 Subject: [PATCH 11/26] Redesigned test suite framework, with timing tests --- .../FSharp.Quotations.Evaluator.Tests.fsproj | 2 +- .../Rosetta.fs | 147 +++++++++++++----- 2 files changed, 108 insertions(+), 41 deletions(-) diff --git a/tests/FSharp.Quotations.Evaluator.Tests/FSharp.Quotations.Evaluator.Tests.fsproj b/tests/FSharp.Quotations.Evaluator.Tests/FSharp.Quotations.Evaluator.Tests.fsproj index 73ba2a9..2277fd8 100644 --- a/tests/FSharp.Quotations.Evaluator.Tests/FSharp.Quotations.Evaluator.Tests.fsproj +++ b/tests/FSharp.Quotations.Evaluator.Tests/FSharp.Quotations.Evaluator.Tests.fsproj @@ -9,7 +9,7 @@ Library FSharp.Quotations.Evaluator.Tests FSharp.Quotations.Evaluator.Tests - v4.0 + v4.5 4.3.0.0 FSharp.Quotations.Evaluator.Tests diff --git a/tests/FSharp.Quotations.Evaluator.Tests/Rosetta.fs b/tests/FSharp.Quotations.Evaluator.Tests/Rosetta.fs index bc5b697..a431913 100644 --- a/tests/FSharp.Quotations.Evaluator.Tests/Rosetta.fs +++ b/tests/FSharp.Quotations.Evaluator.Tests/Rosetta.fs @@ -1,46 +1,75 @@ module FSharp.Quotations.Evaluator.Rosetta open System +open System.Diagnostics +open System.Reflection +open System.Linq.Expressions open NUnit.Framework open Microsoft.FSharp.Quotations open FSharp.Quotations.Evaluator.Unittests open Microsoft.FSharp.Quotations -// [Expanding quotations](http://fssnip.net/bx) -let expand (expr:Expr<'a>) : Expr<'a>= - /// The parameter 'vars' is an immutable map that assigns expressions to variables - /// (as we recursively process the tree, we replace all known variables) - let rec expand vars expr = - // First recursively process & replace variables - let expanded = - match expr with - // If the variable has an assignment, then replace it with the expression - | ExprShape.ShapeVar v when Map.containsKey v vars -> vars.[v] - // Apply 'expand' recursively on all sub-expressions - | ExprShape.ShapeVar v -> Expr.Var v - | Patterns.Call(body, DerivedPatterns.MethodWithReflectedDefinition meth, args) -> - let this = match body with Some b -> Expr.Application(meth, b) | _ -> meth - let res = Expr.Applications(this, [ for a in args -> [a]]) - expand vars res - | ExprShape.ShapeLambda(v, expr) -> - Expr.Lambda(v, expand vars expr) - | ExprShape.ShapeCombination(o, exprs) -> - ExprShape.RebuildShapeCombination(o, List.map (expand vars) exprs) - - // After expanding, try reducing the expression - we can replace 'let' - // expressions and applications where the first argument is lambda - match expanded with - | Patterns.Application(ExprShape.ShapeLambda(v, body), assign) - | Patterns.Let(v, assign, body) -> - expand (Map.add v (expand vars assign) vars) body - | _ -> expanded - - match expand Map.empty expr with - | Patterns.Lambda(v,body) -> Expr.Cast body +type TestIterationsAttribute (count) = + inherit Attribute () + + member __.Count = count + + static member DefaultCount = 10000 + +let getTypedReflectedDefinition (functionQuotation:Expr<'t>) : MethodInfo * Expr<'t> = + match functionQuotation with + | Patterns.Lambda(_,Patterns.Call(_,``method``,_)) -> + match Expr.TryGetReflectedDefinition ``method`` with + | None -> failwith "Badness" + | Some t -> ``method``, Expr.Cast t | _ -> failwith "Unexpected Form" -[] +let getEntryPoints (functionQuotation:Expr't>) = + let ``method``, definition = getTypedReflectedDefinition functionQuotation + + let linqCompiledMethod = definition.Compile () + let directlyCallMethod = Expression.Lambda>(Expression.Call(``method``)).Compile () + + ``method``, linqCompiledMethod, directlyCallMethod + +let testFunction functionQuotation = + let ``method``, compiledMethod, directlyCallMethod = + getEntryPoints functionQuotation + + let viaLinqCompilation = compiledMethod () + let directlyCalled = directlyCallMethod.Invoke () + + check ``method``.Name viaLinqCompilation directlyCalled + +let getIterations (``method``:MethodInfo) = + let testIterations = ``method``.GetCustomAttribute () + if box testIterations = null + then TestIterationsAttribute.DefaultCount + else testIterations.Count + +let timeFunction functionQuotation = + let ``method``, compiledMethod, directlyCallMethod = + getEntryPoints functionQuotation + + compiledMethod () |> ignore + directlyCallMethod.Invoke () |> ignore + + let iterations = getIterations ``method`` + + let sw = Stopwatch.StartNew () + for i=0 to iterations-1 do + compiledMethod () |> ignore + let viaLinqMs = sw.ElapsedMilliseconds + + let sw = Stopwatch.StartNew () + for i=0 to iterations-1 do + directlyCallMethod.Invoke () |> ignore + let directMs = sw.ElapsedMilliseconds + + Assert.LessOrEqual (viaLinqMs, 2L * directMs) + +[] let ``[answerDoors](http://rosettacode.org/wiki/100_doors#F.23)`` () = let ToggleNth n (lst:bool array) = // Toggle every n'th door [(n-1) .. n .. 99] // For each appropriate door @@ -49,6 +78,14 @@ let ``[answerDoors](http://rosettacode.org/wiki/100_doors#F.23)`` () = Seq.iter (fun n -> ToggleNth n doors) [1..100] // toggle the appropriate doors for each pass doors +[] +let ``Test [answerDoors](http://rosettacode.org/wiki/100_doors#F.23)`` () = + testFunction <@ ``[answerDoors](http://rosettacode.org/wiki/100_doors#F.23)`` @> + +[] +let ``Time [answerDoors](http://rosettacode.org/wiki/100_doors#F.23)`` () = + timeFunction <@ ``[answerDoors](http://rosettacode.org/wiki/100_doors#F.23)`` @> + [] let ``[answer2](http://rosettacode.org/wiki/100_doors#F.23)`` () = let PerfectSquare n = @@ -57,14 +94,44 @@ let ``[answer2](http://rosettacode.org/wiki/100_doors#F.23)`` () = [| for i in 1..100 do yield PerfectSquare i |] [] -let ``http://rosettacode.org/wiki/100_doors#F.23`` () = - let quotation = expand <@ ``[answerDoors](http://rosettacode.org/wiki/100_doors#F.23)`` () @> - let result = ``[answerDoors](http://rosettacode.org/wiki/100_doors#F.23)`` () +let ``Test [answer2](http://rosettacode.org/wiki/100_doors#F.23)`` () = + testFunction <@ ``[answer2](http://rosettacode.org/wiki/100_doors#F.23)`` @> - checkEval "1" quotation result +[] +let ``Time [answer2](http://rosettacode.org/wiki/100_doors#F.23)`` () = + timeFunction <@ ``[answer2](http://rosettacode.org/wiki/100_doors#F.23)`` @> - let quotation = expand <@ ``[answer2](http://rosettacode.org/wiki/100_doors#F.23)`` () @> - let result = ``[answer2](http://rosettacode.org/wiki/100_doors#F.23)`` () +[] +let ``[Euler_method](http://rosettacode.org/wiki/Euler_method#F.23)`` () = + let euler f (h : float) t0 y0 = + (t0, y0) + |> Seq.unfold (fun (t, y) -> Some((t,y), ((t + h), (y + h * (f t y))))) + + let newtonCoolíng (_:float) y = -0.07 * (y - 20.0) + + let f = newtonCoolíng + let a = 0.0 + let y0 = 100.0 + let b = 100.0 + let h = 10.0 + (euler newtonCoolíng h a y0) + |> Seq.takeWhile (fun (t,_) -> t <= b) + |> Seq.toList - checkEval "2" quotation result - +[] +let ``Test [Euler_method](http://rosettacode.org/wiki/Euler_method#F.23)`` () = + testFunction <@ ``[Euler_method](http://rosettacode.org/wiki/Euler_method#F.23)`` @> + +[] +let ``Time [Euler_method](http://rosettacode.org/wiki/Euler_method#F.23)`` () = + timeFunction <@ ``[Euler_method](http://rosettacode.org/wiki/Euler_method#F.23)`` @> + + +(* +[] +let ``[]()`` () = + +[] +let ```` () = + testFunction <@ ```` @> +*) \ No newline at end of file From c48082efd6d73e5ff802febd896c2ab87a536fc9 Mon Sep 17 00:00:00 2001 From: Paul Westcott Date: Thu, 6 Nov 2014 16:29:46 +1100 Subject: [PATCH 12/26] Added upper and lower bounds for time tests These are very generous timings to say the least! The linq compiled versions are 30 or some times worse! Lets see what we can do about that... --- .../FSharp.Quotations.Evaluator.Tests.fsproj | 2 +- .../{Rosetta.fs => Performance.fs} | 77 ++++++++++++++----- 2 files changed, 57 insertions(+), 22 deletions(-) rename tests/FSharp.Quotations.Evaluator.Tests/{Rosetta.fs => Performance.fs} (62%) diff --git a/tests/FSharp.Quotations.Evaluator.Tests/FSharp.Quotations.Evaluator.Tests.fsproj b/tests/FSharp.Quotations.Evaluator.Tests/FSharp.Quotations.Evaluator.Tests.fsproj index 2277fd8..9732f64 100644 --- a/tests/FSharp.Quotations.Evaluator.Tests/FSharp.Quotations.Evaluator.Tests.fsproj +++ b/tests/FSharp.Quotations.Evaluator.Tests/FSharp.Quotations.Evaluator.Tests.fsproj @@ -59,7 +59,7 @@ - + diff --git a/tests/FSharp.Quotations.Evaluator.Tests/Rosetta.fs b/tests/FSharp.Quotations.Evaluator.Tests/Performance.fs similarity index 62% rename from tests/FSharp.Quotations.Evaluator.Tests/Rosetta.fs rename to tests/FSharp.Quotations.Evaluator.Tests/Performance.fs index a431913..554fd6e 100644 --- a/tests/FSharp.Quotations.Evaluator.Tests/Rosetta.fs +++ b/tests/FSharp.Quotations.Evaluator.Tests/Performance.fs @@ -1,4 +1,4 @@ -module FSharp.Quotations.Evaluator.Rosetta +module FSharp.Quotations.Evaluator.Performance open System open System.Diagnostics @@ -12,11 +12,14 @@ open Microsoft.FSharp.Quotations type TestIterationsAttribute (count) = inherit Attribute () - member __.Count = count - static member DefaultCount = 10000 +type TimeAllowanceAttribute (multiplier) = + inherit Attribute () + member __.Multiplier = multiplier + static member DefaultMultiplier = 2.0 + let getTypedReflectedDefinition (functionQuotation:Expr<'t>) : MethodInfo * Expr<'t> = match functionQuotation with | Patterns.Lambda(_,Patterns.Call(_,``method``,_)) -> @@ -48,28 +51,60 @@ let getIterations (``method``:MethodInfo) = then TestIterationsAttribute.DefaultCount else testIterations.Count +let getTimeAllowanceMultiplier (``method``:MethodInfo) = + let timeAllowance = ``method``.GetCustomAttribute () + if box timeAllowance = null + then TimeAllowanceAttribute.DefaultMultiplier + else timeAllowance.Multiplier + +// we probably have a lot of ceremony here for no particular reason, but it shouldn't hurt let timeFunction functionQuotation = let ``method``, compiledMethod, directlyCallMethod = getEntryPoints functionQuotation - compiledMethod () |> ignore + // just run them once to 'prime' them to some degree... + compiledMethod () |> ignore directlyCallMethod.Invoke () |> ignore - let iterations = getIterations ``method`` - - let sw = Stopwatch.StartNew () - for i=0 to iterations-1 do - compiledMethod () |> ignore - let viaLinqMs = sw.ElapsedMilliseconds - - let sw = Stopwatch.StartNew () - for i=0 to iterations-1 do - directlyCallMethod.Invoke () |> ignore - let directMs = sw.ElapsedMilliseconds - - Assert.LessOrEqual (viaLinqMs, 2L * directMs) - -[] + let iterations = ``method`` |> getIterations + let timeAllowanceMultiplier = ``method`` |> getTimeAllowanceMultiplier + + let getLinqCompiledTime () = + GC.Collect () + System.Threading.Thread.Sleep(1) // start a time slice afresh; maybe! + let sw = Stopwatch.StartNew () + for i=0 to iterations-1 do + compiledMethod () |> ignore + float sw.ElapsedMilliseconds + + let getDirectelyCompiledTime () = + GC.Collect () + System.Threading.Thread.Sleep(1) // start a time slice afresh; maybe! + let sw = Stopwatch.StartNew () + for i=0 to iterations-1 do + directlyCallMethod.Invoke () |> ignore + float sw.ElapsedMilliseconds + + let directMs, viaLinqMs = + // "randomly" choose one to run first + if DateTime.Now.Millisecond / 100 % 2 = 1 then + getDirectelyCompiledTime(), getLinqCompiledTime () + else + let linqCompiledTime = getLinqCompiledTime () + let directelyCompiledTime = getDirectelyCompiledTime () + directelyCompiledTime, linqCompiledTime + + let allowedTime = directMs * timeAllowanceMultiplier + + Assert.LessOrEqual (viaLinqMs, allowedTime, + "Took too long! linq={0:0} compiled={1:0} multiples of allowed time={2:0.00}", + viaLinqMs, directMs, viaLinqMs / allowedTime) + + Assert.GreaterOrEqual (viaLinqMs, allowedTime * 0.75, + "Too fast; decrease the multiplier! linq={0:0} compiled={1:0} allowed multiples={2:0.00}-{3:0.00} actual multiples={4:0.00}", + viaLinqMs, directMs, timeAllowanceMultiplier * 0.75, timeAllowanceMultiplier, viaLinqMs / directMs) + +[] let ``[answerDoors](http://rosettacode.org/wiki/100_doors#F.23)`` () = let ToggleNth n (lst:bool array) = // Toggle every n'th door [(n-1) .. n .. 99] // For each appropriate door @@ -86,7 +121,7 @@ let ``Test [answerDoors](http://rosettacode.org/wiki/100_doors#F.23)`` () = let ``Time [answerDoors](http://rosettacode.org/wiki/100_doors#F.23)`` () = timeFunction <@ ``[answerDoors](http://rosettacode.org/wiki/100_doors#F.23)`` @> -[] +[] let ``[answer2](http://rosettacode.org/wiki/100_doors#F.23)`` () = let PerfectSquare n = let sqrt = int(Math.Sqrt(float n)) @@ -101,7 +136,7 @@ let ``Test [answer2](http://rosettacode.org/wiki/100_doors#F.23)`` () = let ``Time [answer2](http://rosettacode.org/wiki/100_doors#F.23)`` () = timeFunction <@ ``[answer2](http://rosettacode.org/wiki/100_doors#F.23)`` @> -[] +[] let ``[Euler_method](http://rosettacode.org/wiki/Euler_method#F.23)`` () = let euler f (h : float) t0 y0 = (t0, y0) From 8d3d8686e58bd5bdac2edf5d327a64f458bb9b8e Mon Sep 17 00:00:00 2001 From: Paul Westcott Date: Thu, 6 Nov 2014 19:19:30 +1100 Subject: [PATCH 13/26] Added some tests for basic operations Operations on non-int types are abysmal! --- .../QuotationsEvaluator.fs | 4 +- .../Performance.fs | 107 +++++++++++++++++- 2 files changed, 108 insertions(+), 3 deletions(-) diff --git a/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fs b/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fs index 40bfd63..43ebf79 100644 --- a/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fs +++ b/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fs @@ -634,7 +634,9 @@ module QuotationEvaluationTypes = build tupTy argsP | Patterns.IfThenElse(g,t,e) -> - Expression.Condition(ConvExpr env g, ConvExpr env t,ConvExpr env e) |> asExpr + match e with + | Patterns.Value(o,_) when o = null -> Expression.IfThen (ConvExpr env g, ConvExpr env t)|> asExpr + | _ -> Expression.Condition(ConvExpr env g, ConvExpr env t,ConvExpr env e) |> asExpr | Patterns.Sequential (e1,e2) -> let e1P = ConvExpr env e1 diff --git a/tests/FSharp.Quotations.Evaluator.Tests/Performance.fs b/tests/FSharp.Quotations.Evaluator.Tests/Performance.fs index 554fd6e..0bdcd0b 100644 --- a/tests/FSharp.Quotations.Evaluator.Tests/Performance.fs +++ b/tests/FSharp.Quotations.Evaluator.Tests/Performance.fs @@ -162,11 +162,114 @@ let ``Time [Euler_method](http://rosettacode.org/wiki/Euler_method#F.23)`` () = timeFunction <@ ``[Euler_method](http://rosettacode.org/wiki/Euler_method#F.23)`` @> +[] +let ``int Operators +-/*%`` () = + let rand = Random 3141592 + let mutable result = 0 + for i = 1 to 10000 do + let mutable x = rand.Next () + x <- x / i + x <- x + i + x <- x * i + x <- x - i + if x % 2 = 1 then + result <- result + 1 + result + +[] +let ``Test int Operators +-/*%`` () = + testFunction <@ ``int Operators +-/*%`` @> + +[] +let ``Time int Operators +-/*%`` () = + timeFunction <@ ``int Operators +-/*%`` @> + +[] +let ``int64 Operators +-/*%`` () = + let rand = Random 3141592 + let mutable result = 0L + for i = 1 to 10000 do + let mutable x = int64 <| rand.Next () + let i = int64 i + x <- x / i + x <- x + i + x <- x * i + x <- x - i + if x % 2L = 1L then + result <- result + 1L + result + +[] +let ``Test int64 Operators +-/*%`` () = + testFunction <@ ``int64 Operators +-/*%`` @> + +[] +let ``Time int64 Operators +-/*%`` () = + timeFunction <@ ``int64 Operators +-/*%`` @> + + + +[] +let ``float Operators +-/*%`` () = + let rand = Random 3141592 + let mutable result = 0.0 + for i = 1 to 10000 do + let mutable x = float <| rand.Next () + let i = float i + x <- x / i + x <- x + i + x <- x * i + x <- x - i + if x % 2.0 = 1.0 then + result <- result + 1.0 + result + +[] +let ``Test float Operators +-/*%`` () = + testFunction <@ ``float Operators +-/*%`` @> + +[] +let ``Time float Operators +-/*%`` () = + timeFunction <@ ``float Operators +-/*%`` @> + + +(* +fails to run compiled version; I think because of Microsoft.FSharp.Core.ExtraTopLevelOperators.ToSingle + +[] +let ``single Operators +-/*%`` () = + let rand = Random 3141592 + let mutable result = 0.0 + for i = 1 to 10000 do + let mutable x = single <| rand.Next () + let i = single i + x <- x / i + x <- x + i + x <- x * i + x <- x - i + if x % 2.0f = 1.0f then + result <- result + 1.0 + result + +[] +let ``Test single Operators +-/*%`` () = + testFunction <@ ``single Operators +-/*%`` @> + +[] +let ``Time single Operators +-/*%`` () = + timeFunction <@ ``single Operators +-/*%`` @> +*) + + (* [] let ``[]()`` () = [] -let ```` () = - testFunction <@ ```` @> +let `` `` () = + testFunction <@ `` `` @> + +[] +let `` `` () = + timeFunction <@ `` `` @> *) \ No newline at end of file From 61ec2bf604d5ba60f01a3eb0ae8429559f6202c5 Mon Sep 17 00:00:00 2001 From: Paul Westcott Date: Thu, 6 Nov 2014 19:28:39 +1100 Subject: [PATCH 14/26] Performance increase by allowing Primitives to use default comparisons --- .../QuotationsEvaluator.fs | 32 +++++-------------- .../Performance.fs | 4 +-- 2 files changed, 10 insertions(+), 26 deletions(-) diff --git a/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fs b/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fs index 43ebf79..ac7b905 100644 --- a/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fs +++ b/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fs @@ -323,13 +323,6 @@ module QuotationEvaluationTypes = else e - let (|GenericEqualityQ|_|) = (|SpecificCall|_|) <@ LanguagePrimitives.GenericEquality @> - let (|EqualsQ|_|) = (|SpecificCall|_|) <@ ( = ) @> - let (|GreaterQ|_|) = (|SpecificCall|_|) <@ ( > ) @> - let (|GreaterEqQ|_|) = (|SpecificCall|_|) <@ ( >=) @> - let (|LessQ|_|) = (|SpecificCall|_|) <@ ( <) @> - let (|LessEqQ|_|) = (|SpecificCall|_|) <@ ( <=) @> - let (|NotEqQ|_|) = (|SpecificCall|_|) <@ ( <>) @> let (|NotQ|_|) = (|SpecificCall|_|) <@ not @> let (|NegQ|_|) = (|SpecificCall|_|) <@ ( ~-) : int -> int @> let (|PlusQ|_|) = (|SpecificCall|_|) <@ ( + ) @> @@ -450,7 +443,7 @@ module QuotationEvaluationTypes = let e1 = ConvExpr env x1 let e2 = ConvExpr env x2 - if env.eraseEquality then + if e1.Type.IsPrimitive || env.eraseEquality then exprErasedConstructor(e1,e2) |> asExpr else exprConstructor(e1, e2, false, intrinsic.MakeGenericMethod([|x1.Type|])) |> asExpr @@ -460,22 +453,13 @@ module QuotationEvaluationTypes = | PlusQ (_, [ty1;ty2;ty3],[x1;x2]) when (ty1 = typeof) && (ty2 = typeof) -> ConvExpr env (<@@ System.String.Concat( [| %%x1 ; %%x2 |] : string array ) @@>) - //| SpecificCall <@ LanguagePrimitives.GenericEquality @>([ty1],[x1;x2]) - //| SpecificCall <@ ( = ) @>([ty1],[x1;x2]) when (ty1 = typeof) -> - // ConvExpr env (<@@ System.String.op_Equality(%%x1,%%x2) @@>) - - | GenericEqualityQ (_, _,[x1;x2]) - | EqualsQ (_, _,[x1;x2]) -> transComparison x1 x2 Expression.Equal Expression.Equal genericEqualityIntrinsic - - | GreaterQ (_, _,[x1;x2]) -> transComparison x1 x2 Expression.GreaterThan Expression.GreaterThan genericGreaterThanIntrinsic - - | GreaterEqQ (_, _,[x1;x2]) -> transComparison x1 x2 Expression.GreaterThanOrEqual Expression.GreaterThanOrEqual genericGreaterOrEqualIntrinsic - - | LessQ (_, _,[x1;x2]) -> transComparison x1 x2 Expression.LessThan Expression.LessThan genericLessThanIntrinsic - - | LessEqQ (_, _,[x1;x2]) -> transComparison x1 x2 Expression.LessThanOrEqual Expression.LessThanOrEqual genericLessOrEqualIntrinsic - - | NotEqQ (_, _,[x1;x2]) -> transComparison x1 x2 Expression.NotEqual Expression.NotEqual genericNotEqualIntrinsic + | SpecificCall <@ LanguagePrimitives.GenericEquality @> (_, _,[x1;x2]) + | SpecificCall <@ ( = ) @> (_,_,[x1;x2]) -> transComparison x1 x2 Expression.Equal Expression.Equal genericEqualityIntrinsic + | SpecificCall <@ ( > ) @> (_,_,[x1;x2]) -> transComparison x1 x2 Expression.GreaterThan Expression.GreaterThan genericGreaterThanIntrinsic + | SpecificCall <@ ( >= ) @> (_,_,[x1;x2]) -> transComparison x1 x2 Expression.GreaterThanOrEqual Expression.GreaterThanOrEqual genericGreaterOrEqualIntrinsic + | SpecificCall <@ ( < ) @> (_,_,[x1;x2]) -> transComparison x1 x2 Expression.LessThan Expression.LessThan genericLessThanIntrinsic + | SpecificCall <@ ( <= ) @> (_,_,[x1;x2]) -> transComparison x1 x2 Expression.LessThanOrEqual Expression.LessThanOrEqual genericLessOrEqualIntrinsic + | SpecificCall <@ ( <> ) @> (_,_,[x1;x2]) -> transComparison x1 x2 Expression.NotEqual Expression.NotEqual genericNotEqualIntrinsic | NotQ (_, _,[x1]) -> Expression.Not(ConvExpr env x1) |> asExpr diff --git a/tests/FSharp.Quotations.Evaluator.Tests/Performance.fs b/tests/FSharp.Quotations.Evaluator.Tests/Performance.fs index 0bdcd0b..17e9cbd 100644 --- a/tests/FSharp.Quotations.Evaluator.Tests/Performance.fs +++ b/tests/FSharp.Quotations.Evaluator.Tests/Performance.fs @@ -136,7 +136,7 @@ let ``Test [answer2](http://rosettacode.org/wiki/100_doors#F.23)`` () = let ``Time [answer2](http://rosettacode.org/wiki/100_doors#F.23)`` () = timeFunction <@ ``[answer2](http://rosettacode.org/wiki/100_doors#F.23)`` @> -[] +[] let ``[Euler_method](http://rosettacode.org/wiki/Euler_method#F.23)`` () = let euler f (h : float) t0 y0 = (t0, y0) @@ -162,7 +162,7 @@ let ``Time [Euler_method](http://rosettacode.org/wiki/Euler_method#F.23)`` () = timeFunction <@ ``[Euler_method](http://rosettacode.org/wiki/Euler_method#F.23)`` @> -[] +[] let ``int Operators +-/*%`` () = let rand = Random 3141592 let mutable result = 0 From 2fa8530ae3f8b55980198d68744dabd156f8a74c Mon Sep 17 00:00:00 2001 From: Paul Westcott Date: Thu, 6 Nov 2014 19:57:58 +1100 Subject: [PATCH 15/26] Added some tests for comparisons and casts --- .../Performance.fs | 158 +++++++++++++++++- 1 file changed, 155 insertions(+), 3 deletions(-) diff --git a/tests/FSharp.Quotations.Evaluator.Tests/Performance.fs b/tests/FSharp.Quotations.Evaluator.Tests/Performance.fs index 17e9cbd..046c4a2 100644 --- a/tests/FSharp.Quotations.Evaluator.Tests/Performance.fs +++ b/tests/FSharp.Quotations.Evaluator.Tests/Performance.fs @@ -104,6 +104,7 @@ let timeFunction functionQuotation = "Too fast; decrease the multiplier! linq={0:0} compiled={1:0} allowed multiples={2:0.00}-{3:0.00} actual multiples={4:0.00}", viaLinqMs, directMs, timeAllowanceMultiplier * 0.75, timeAllowanceMultiplier, viaLinqMs / directMs) + [] let ``[answerDoors](http://rosettacode.org/wiki/100_doors#F.23)`` () = let ToggleNth n (lst:bool array) = // Toggle every n'th door @@ -121,6 +122,7 @@ let ``Test [answerDoors](http://rosettacode.org/wiki/100_doors#F.23)`` () = let ``Time [answerDoors](http://rosettacode.org/wiki/100_doors#F.23)`` () = timeFunction <@ ``[answerDoors](http://rosettacode.org/wiki/100_doors#F.23)`` @> + [] let ``[answer2](http://rosettacode.org/wiki/100_doors#F.23)`` () = let PerfectSquare n = @@ -136,7 +138,8 @@ let ``Test [answer2](http://rosettacode.org/wiki/100_doors#F.23)`` () = let ``Time [answer2](http://rosettacode.org/wiki/100_doors#F.23)`` () = timeFunction <@ ``[answer2](http://rosettacode.org/wiki/100_doors#F.23)`` @> -[] + +[] let ``[Euler_method](http://rosettacode.org/wiki/Euler_method#F.23)`` () = let euler f (h : float) t0 y0 = (t0, y0) @@ -184,6 +187,7 @@ let ``Test int Operators +-/*%`` () = let ``Time int Operators +-/*%`` () = timeFunction <@ ``int Operators +-/*%`` @> + [] let ``int64 Operators +-/*%`` () = let rand = Random 3141592 @@ -208,7 +212,6 @@ let ``Time int64 Operators +-/*%`` () = timeFunction <@ ``int64 Operators +-/*%`` @> - [] let ``float Operators +-/*%`` () = let rand = Random 3141592 @@ -232,7 +235,6 @@ let ``Test float Operators +-/*%`` () = let ``Time float Operators +-/*%`` () = timeFunction <@ ``float Operators +-/*%`` @> - (* fails to run compiled version; I think because of Microsoft.FSharp.Core.ExtraTopLevelOperators.ToSingle @@ -261,6 +263,156 @@ let ``Time single Operators +-/*%`` () = *) +[] +let ``int Operators <>=`` () = + let rand = Random 3141592 + let mutable result = 0 + for i = 1 to 1000 do + let a = rand.Next () + let b = rand.Next () + let c = rand.Next () + let d = rand.Next () + let e = rand.Next 3 + let f = rand.Next 3 + let g = rand.Next 3 + if a < b then result <- result + 1 + if b > c then result <- result - 1 + if a >= c then result <- result + 2 + if a <= d then result <- result - 2 + if e = f then result <- result + 3 + if f <> g then result <- result - 3 + result + +[] +let ``Test int Operators <>=`` () = + testFunction <@ ``int Operators <>=`` @> + +[] +let ``Time int Operators <>=`` () = + timeFunction <@ ``int Operators <>=`` @> + + +[] +let ``int64 Operators <>=`` () = + let rand = Random 3141592 + let mutable result = 0 + for i = 1 to 1000 do + let a = rand.Next () + let b = rand.Next () + let c = rand.Next () + let d = rand.Next () + let e = rand.Next 3 + let f = rand.Next 3 + let g = rand.Next 3 + if a < b then result <- result + 1 + if b > c then result <- result - 1 + if a >= c then result <- result + 2 + if a <= d then result <- result - 2 + if e = f then result <- result + 3 + if f <> g then result <- result - 3 + result + +[] +let ``Test int64 Operators <>=`` () = + testFunction <@ ``int64 Operators <>=`` @> + +[] +let ``Time int64 Operators <>=`` () = + timeFunction <@ ``int64 Operators <>=`` @> + + +[] +let ``float Operators <>=`` () = + let rand = Random 3141592 + let mutable result = 0 + for i = 1 to 1000 do + let a = rand.Next () + let b = rand.Next () + let c = rand.Next () + let d = rand.Next () + let e = rand.Next 3 + let f = rand.Next 3 + let g = rand.Next 3 + if a < b then result <- result + 1 + if b > c then result <- result - 1 + if a >= c then result <- result + 2 + if a <= d then result <- result - 2 + if e = f then result <- result + 3 + if f <> g then result <- result - 3 + result + +[] +let ``Test float Operators <>=`` () = + testFunction <@ ``float Operators <>=`` @> + +[] +let ``Time float Operators <>=`` () = + timeFunction <@ ``float Operators <>=`` @> + + +[] +let ``single Operators <>=`` () = + let rand = Random 3141592 + let mutable result = 0 + for i = 1 to 1000 do + let a = rand.Next () + let b = rand.Next () + let c = rand.Next () + let d = rand.Next () + let e = rand.Next 3 + let f = rand.Next 3 + let g = rand.Next 3 + if a < b then result <- result + 1 + if b > c then result <- result - 1 + if a >= c then result <- result + 2 + if a <= d then result <- result - 2 + if e = f then result <- result + 3 + if f <> g then result <- result - 3 + result + +[] +let ``Test single Operators <>=`` () = + testFunction <@ ``single Operators <>=`` @> + +[] +let ``Time single Operators <>=`` () = + timeFunction <@ ``single Operators <>=`` @> + + +[] +let ``float cast`` () = + let rand = Random 3141592 + let mutable total = 0.0 + for i=0 to 1000 do + total <- total + (float (rand.Next ())) + total + +[] +let ``Test float cast`` () = + testFunction <@ ``float cast`` @> + +[] +let ``Time float cast`` () = + timeFunction <@ ``float cast`` @> + + +[] +let ``int64 cast`` () = + let rand = Random 3141592 + let mutable total = 0L + for i=0 to 1000 do + total <- total + (int64 (rand.Next ())) + total + +[] +let ``Test int64 cast`` () = + testFunction <@ ``int64 cast`` @> + +[] +let ``Time int64 cast`` () = + timeFunction <@ ``int64 cast`` @> + + (* [] let ``[]()`` () = From 8811640b22661824b1cff7bae1c5d7b579700311 Mon Sep 17 00:00:00 2001 From: Paul Westcott Date: Thu, 6 Nov 2014 20:16:47 +1100 Subject: [PATCH 16/26] The pipe |> and <| have horrible performance Added tests; now need to fix... --- .../Performance.fs | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/tests/FSharp.Quotations.Evaluator.Tests/Performance.fs b/tests/FSharp.Quotations.Evaluator.Tests/Performance.fs index 046c4a2..a8ffde2 100644 --- a/tests/FSharp.Quotations.Evaluator.Tests/Performance.fs +++ b/tests/FSharp.Quotations.Evaluator.Tests/Performance.fs @@ -413,6 +413,56 @@ let ``Time int64 cast`` () = timeFunction <@ ``int64 cast`` @> +[] +let ``id function`` () = + let rand = Random 3141592 + let mutable total = 0 + for i = 0 to 1000 do + total <- id (rand.Next ()) + total + +[] +let ``Test id function`` () = + testFunction <@ ``id function`` @> + +[] +let ``Time id function`` () = + timeFunction <@ ``id function`` @> + + +[] +let ``operator |>`` () = + let rand = Random 3141592 + let mutable total = 0 + for i = 0 to 1000 do + total <- (rand.Next ()) |> id + total + +[] +let ``Test operator |>`` () = + testFunction <@ ``operator |>`` @> + +[] +let ``Time operator |>`` () = + timeFunction <@ ``operator |>`` @> + + +[] +let ``operator <|`` () = + let rand = Random 3141592 + let mutable total = 0 + for i = 0 to 1000 do + total <- id <| (rand.Next ()) + total + +[] +let ``Test operator <|`` () = + testFunction <@ ``operator <|`` @> + +[] +let ``Time operator <|`` () = + timeFunction <@ ``operator <|`` @> + (* [] let ``[]()`` () = From 652019eaeef382d7329534a120963d12a68fa6ba Mon Sep 17 00:00:00 2001 From: Paul Westcott Date: Mon, 10 Nov 2014 20:37:14 +1100 Subject: [PATCH 17/26] Use OptimizedClosures.FSharpFunc derived class If Lambdas don't require capturing extra state, then create an instance of a class that derives from OptimizedClosures.FSharpFunc. --- .../QuotationsEvaluator.fs | 97 +++++++++++++++++-- .../Performance.fs | 10 +- 2 files changed, 94 insertions(+), 13 deletions(-) diff --git a/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fs b/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fs index ac7b905..cb91f04 100644 --- a/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fs +++ b/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fs @@ -284,6 +284,33 @@ module QuotationEvaluationTypes = f8hole := f8 B.Invoke(f1,f2,f3,f4,f5,f6,f7,f8) + type FuncFSharp<'a> (f:Func<'a>) = + inherit FSharpFunc() + override __.Invoke _ = f.Invoke() + + type FuncFSharp<'a,'b> (f:Func<'a, 'b>) = + inherit FSharpFunc<'a,'b>() + override __.Invoke a = f.Invoke a + + type FuncFSharp<'a,'b,'c> (f:Func<'a,'b,'c>) = + inherit OptimizedClosures.FSharpFunc<'a,'b,'c>() + override __.Invoke (a,b) = f.Invoke (a,b) + override __.Invoke a = fun b -> f.Invoke (a,b) + + type FuncFSharp<'a,'b,'c,'d> (f:Func<'a,'b,'c,'d>) = + inherit OptimizedClosures.FSharpFunc<'a,'b,'c,'d>() + override __.Invoke (a,b,c) = f.Invoke (a,b,c) + override __.Invoke a = fun b c -> f.Invoke (a,b,c) + + type FuncFSharp<'a,'b,'c,'d,'e> (f:Func<'a,'b,'c,'d,'e>) = + inherit OptimizedClosures.FSharpFunc<'a,'b,'c,'d,'e>() + override __.Invoke (a,b,c,d) = f.Invoke (a,b,c,d) + override __.Invoke a = fun b c d -> f.Invoke (a,b,c,d) + + type FuncFSharp<'a,'b,'c,'d,'e,'f> (f:Func<'a,'b,'c,'d,'e,'f>) = + inherit OptimizedClosures.FSharpFunc<'a,'b,'c,'d,'e,'f>() + override __.Invoke (a,b,c,d,e) = f.Invoke (a,b,c,d,e) + override __.Invoke a = fun b c d e -> f.Invoke (a,b,c,d,e) let IsVoidType (ty:System.Type) = (ty = typeof) @@ -642,14 +669,68 @@ module QuotationEvaluationTypes = let linqValue = ConvExpr env value Expression.Assign (linqVariable, linqValue)|> asExpr - | Patterns.Lambda(v,body) -> - let vP = ConvVar v - let env = { env with varEnv = Map.add v (vP |> asExpr) env.varEnv } - let tyargs = [| v.Type; body.Type |] - let bodyP = ConvExpr env body - let convType = typedefof>.MakeGenericType tyargs - let convDelegate = Expression.Lambda(convType, bodyP, [| vP |]) |> asExpr - Expression.Call(typeof,"ToFSharpFunc",tyargs,[| convDelegate |]) |> asExpr + | Patterns.Lambda(firstVar, firstBody) as lambda -> + let rec getVars vars maybeBody = function + | Lambda (v, body) -> getVars (v::vars) (Some body) body + | _ -> List.rev vars, maybeBody.Value + + let vars, body = getVars [] None lambda + + let freeVars = Set (body.GetFreeVars ()) + + let freeVarsCount = freeVars.Count + if freeVarsCount <= 5 && freeVarsCount = vars.Length && vars |> List.forall freeVars.Contains then + let varParameters = + vars + |> List.map (fun var -> var, Expression.Parameter (var.Type, var.Name)) + + let env = + { env with + varEnv = + (env.varEnv, varParameters) + ||> List.fold (fun varEnv (var, parameter) -> + varEnv + |> Map.add var (parameter |> asExpr)) } + + let linqBody = ConvExpr env body + + let parameters = + varParameters + |> List.map snd + + let ``function`` = + Expression.Lambda (linqBody, parameters) + |> fun lambda -> lambda.Compile () + + let funcFSharp = + if freeVarsCount = 1 then typedefof> + elif freeVarsCount = 2 then typedefof> + elif freeVarsCount = 3 then typedefof> + elif freeVarsCount = 4 then typedefof> + elif freeVarsCount = 5 then typedefof> + else failwith "Logic error" + + let parameterTypes = + [| yield! varParameters |> List.map (fun (vars,_) -> vars.Type) + yield linqBody.Type |] + + let ``type`` = funcFSharp.MakeGenericType parameterTypes + + let ``constructor`` = ``type``.GetConstructor [| ``function``.GetType () |] + + let obj = ``constructor``.Invoke [| ``function`` |] + + Expression.Constant (obj) |> asExpr + else + let v, body = firstVar, firstBody + + let vP = ConvVar v + let env = { env with varEnv = Map.add v (vP |> asExpr) env.varEnv } + let tyargs = [| v.Type; body.Type |] + let bodyP = ConvExpr env body + let convType = typedefof>.MakeGenericType tyargs + let convDelegate = Expression.Lambda(convType, bodyP, [| vP |]) |> asExpr + Expression.Call(typeof,"ToFSharpFunc",tyargs,[| convDelegate |]) |> asExpr | Patterns.WhileLoop(condition, iteration) -> let linqCondition = ConvExpr env condition diff --git a/tests/FSharp.Quotations.Evaluator.Tests/Performance.fs b/tests/FSharp.Quotations.Evaluator.Tests/Performance.fs index a8ffde2..237eb2e 100644 --- a/tests/FSharp.Quotations.Evaluator.Tests/Performance.fs +++ b/tests/FSharp.Quotations.Evaluator.Tests/Performance.fs @@ -139,7 +139,7 @@ let ``Time [answer2](http://rosettacode.org/wiki/100_doors#F.23)`` () = timeFunction <@ ``[answer2](http://rosettacode.org/wiki/100_doors#F.23)`` @> -[] +[] let ``[Euler_method](http://rosettacode.org/wiki/Euler_method#F.23)`` () = let euler f (h : float) t0 y0 = (t0, y0) @@ -188,7 +188,7 @@ let ``Time int Operators +-/*%`` () = timeFunction <@ ``int Operators +-/*%`` @> -[] +[] let ``int64 Operators +-/*%`` () = let rand = Random 3141592 let mutable result = 0L @@ -212,7 +212,7 @@ let ``Time int64 Operators +-/*%`` () = timeFunction <@ ``int64 Operators +-/*%`` @> -[] +[] let ``float Operators +-/*%`` () = let rand = Random 3141592 let mutable result = 0.0 @@ -430,7 +430,7 @@ let ``Time id function`` () = timeFunction <@ ``id function`` @> -[] +[] let ``operator |>`` () = let rand = Random 3141592 let mutable total = 0 @@ -447,7 +447,7 @@ let ``Time operator |>`` () = timeFunction <@ ``operator |>`` @> -[] +[] let ``operator <|`` () = let rand = Random 3141592 let mutable total = 0 From e8f1fcc830f3e35bcbe4d501644daaa5c44e82fb Mon Sep 17 00:00:00 2001 From: Paul Westcott Date: Tue, 11 Nov 2014 20:54:15 +1100 Subject: [PATCH 18/26] Also captured state in the FuncFSharp object --- .../QuotationsEvaluator.fs | 141 ++++++++++++------ .../FSharp.Quotations.Evaluator.Tests.fsproj | 1 + .../Performance.fs | 2 +- 3 files changed, 101 insertions(+), 43 deletions(-) diff --git a/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fs b/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fs index cb91f04..584e476 100644 --- a/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fs +++ b/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fs @@ -284,33 +284,33 @@ module QuotationEvaluationTypes = f8hole := f8 B.Invoke(f1,f2,f3,f4,f5,f6,f7,f8) - type FuncFSharp<'a> (f:Func<'a>) = + type FuncFSharp<'state,'a> (f:Func<'state,'a>, state:'state) = inherit FSharpFunc() - override __.Invoke _ = f.Invoke() + override __.Invoke _ = f.Invoke state - type FuncFSharp<'a,'b> (f:Func<'a, 'b>) = + type FuncFSharp<'state,'a,'b> (f:Func<'state,'a,'b>, state:'state) = inherit FSharpFunc<'a,'b>() - override __.Invoke a = f.Invoke a + override __.Invoke a = f.Invoke (state,a) - type FuncFSharp<'a,'b,'c> (f:Func<'a,'b,'c>) = + type FuncFSharp<'state,'a,'b,'c> (f:Func<'state,'a,'b,'c>, state:'state) = inherit OptimizedClosures.FSharpFunc<'a,'b,'c>() - override __.Invoke (a,b) = f.Invoke (a,b) - override __.Invoke a = fun b -> f.Invoke (a,b) + override __.Invoke (a,b) = f.Invoke (state,a,b) + override this.Invoke a = fun b -> this.Invoke (a,b) - type FuncFSharp<'a,'b,'c,'d> (f:Func<'a,'b,'c,'d>) = + type FuncFSharp<'state,'a,'b,'c,'d> (f:Func<'state,'a,'b,'c,'d>, state:'state) = inherit OptimizedClosures.FSharpFunc<'a,'b,'c,'d>() - override __.Invoke (a,b,c) = f.Invoke (a,b,c) - override __.Invoke a = fun b c -> f.Invoke (a,b,c) + override __.Invoke (a,b,c) = f.Invoke (state,a,b,c) + override this.Invoke a = fun b c -> this.Invoke (a,b,c) - type FuncFSharp<'a,'b,'c,'d,'e> (f:Func<'a,'b,'c,'d,'e>) = + type FuncFSharp<'state,'a,'b,'c,'d,'e> (f:Func<'state,'a,'b,'c,'d,'e>, state:'state) = inherit OptimizedClosures.FSharpFunc<'a,'b,'c,'d,'e>() - override __.Invoke (a,b,c,d) = f.Invoke (a,b,c,d) - override __.Invoke a = fun b c d -> f.Invoke (a,b,c,d) + override __.Invoke (a,b,c,d) = f.Invoke (state,a,b,c,d) + override this.Invoke a = fun b c d -> this.Invoke (a,b,c,d) - type FuncFSharp<'a,'b,'c,'d,'e,'f> (f:Func<'a,'b,'c,'d,'e,'f>) = + type FuncFSharp<'state,'a,'b,'c,'d,'e,'f> (f:Func<'state,'a,'b,'c,'d,'e,'f>, state:'state) = inherit OptimizedClosures.FSharpFunc<'a,'b,'c,'d,'e,'f>() - override __.Invoke (a,b,c,d,e) = f.Invoke (a,b,c,d,e) - override __.Invoke a = fun b c d e -> f.Invoke (a,b,c,d,e) + override __.Invoke (a,b,c,d,e) = f.Invoke (state,a,b,c,d,e) + override this.Invoke a = fun b c d e -> this.Invoke (a,b,c,d,e) let IsVoidType (ty:System.Type) = (ty = typeof) @@ -676,51 +676,105 @@ module QuotationEvaluationTypes = let vars, body = getVars [] None lambda - let freeVars = Set (body.GetFreeVars ()) + let capturedVars = + let parameterVars = Set vars + + body.GetFreeVars () + |> Seq.filter (fun freeVar -> not <| Set.contains freeVar parameterVars) + |> Seq.sortBy (fun freeVar -> freeVar.Name) + |> Seq.toList + + let varsCount = vars.Length + if varsCount <= 5 && capturedVars.Length <= 8 then + let stateType = + match capturedVars with + | [] -> typeof + | v1::[] -> v1.Type + | v1::v2::[] -> typedefof>. MakeGenericType(v1.Type,v2.Type) + | v1::v2::v3::[] -> typedefof>. MakeGenericType(v1.Type,v2.Type,v3.Type) + | v1::v2::v3::v4::[] -> typedefof>. MakeGenericType(v1.Type,v2.Type,v3.Type,v4.Type) + | v1::v2::v3::v4::v5::[] -> typedefof>. MakeGenericType(v1.Type,v2.Type,v3.Type,v4.Type,v5.Type) + | v1::v2::v3::v4::v5::v6::[] -> typedefof>. MakeGenericType(v1.Type,v2.Type,v3.Type,v4.Type,v5.Type,v6.Type) + | v1::v2::v3::v4::v5::v6::v7::[] -> typedefof>. MakeGenericType(v1.Type,v2.Type,v3.Type,v4.Type,v5.Type,v6.Type,v7.Type) + | v1::v2::v3::v4::v5::v6::v7::v8::[] -> typedefof>.MakeGenericType(v1.Type,v2.Type,v3.Type,v4.Type,v5.Type,v6.Type,v7.Type,v8.Type) + | _ -> failwith "Not currently supported" + + let stateParameter = + Expression.Parameter (stateType, "state") + + let stateEnvironment = + match capturedVars with + | [] -> [] + | v1 :: [] -> [v1, stateParameter |> asExpr] + | _ -> + capturedVars + |> List.mapi (fun idx var -> var, Expression.Property (stateParameter, "Item" + (idx+1).ToString()) |> asExpr) - let freeVarsCount = freeVars.Count - if freeVarsCount <= 5 && freeVarsCount = vars.Length && vars |> List.forall freeVars.Contains then let varParameters = vars |> List.map (fun var -> var, Expression.Parameter (var.Type, var.Name)) - let env = + let lambdaEnv = { env with varEnv = - (env.varEnv, varParameters) + let environmentVariables = + varParameters + |> List.map (fun (v,p) -> v, p |> asExpr) + |> List.append stateEnvironment + + (env.varEnv, environmentVariables) ||> List.fold (fun varEnv (var, parameter) -> varEnv - |> Map.add var (parameter |> asExpr)) } + |> Map.add var parameter) } - let linqBody = ConvExpr env body + let linqBody = ConvExpr lambdaEnv body let parameters = - varParameters - |> List.map snd + [ yield stateParameter + yield! varParameters |> List.map snd ] + + let linqLambda = Expression.Lambda (linqBody, parameters) - let ``function`` = - Expression.Lambda (linqBody, parameters) - |> fun lambda -> lambda.Compile () + let ``function`` = linqLambda.Compile () let funcFSharp = - if freeVarsCount = 1 then typedefof> - elif freeVarsCount = 2 then typedefof> - elif freeVarsCount = 3 then typedefof> - elif freeVarsCount = 4 then typedefof> - elif freeVarsCount = 5 then typedefof> + if varsCount = 1 then typedefof> + elif varsCount = 2 then typedefof> + elif varsCount = 3 then typedefof> + elif varsCount = 4 then typedefof> + elif varsCount = 5 then typedefof> else failwith "Logic error" let parameterTypes = - [| yield! varParameters |> List.map (fun (vars,_) -> vars.Type) + [| yield stateType + yield! varParameters |> List.map (fun (vars,_) -> vars.Type) yield linqBody.Type |] let ``type`` = funcFSharp.MakeGenericType parameterTypes - let ``constructor`` = ``type``.GetConstructor [| ``function``.GetType () |] - - let obj = ``constructor``.Invoke [| ``function`` |] - - Expression.Constant (obj) |> asExpr + let ``constructor`` = ``type``.GetConstructor [| ``function``.GetType (); stateType |] + + match capturedVars with + | [] -> + let obj = ``constructor``.Invoke [| ``function``; null |] + Expression.Constant (obj) |> asExpr + | v1 :: [] -> + let state = Map.find v1 env.varEnv + Expression.New (``constructor``, [Expression.Constant(``function``) |> asExpr; state]) |> asExpr + | _ -> + let state = + capturedVars + |> List.map (fun var -> Map.find var env.varEnv) + + let stateConstructor = + let types = + capturedVars + |> List.map (fun var -> var.Type) + |> List.toArray + + stateType.GetConstructor types + + Expression.New (``constructor``, [Expression.Constant(``function``) |> asExpr; Expression.New(stateConstructor, state) |> asExpr]) |> asExpr else let v, body = firstVar, firstBody @@ -890,11 +944,14 @@ module QuotationEvaluationTypes = //printf "** Expression .Parameter(%a, %a)\n" output_any ty output_any nm; Expression.Parameter(v.Type, v.Name) - let Conv (e: #Expr,eraseEquality) = ConvExpr { eraseEquality = eraseEquality; varEnv = Map.empty } (e :> Expr) + let Conv (e: #Expr,eraseEquality) = + let linqExpr = ConvExpr { eraseEquality = eraseEquality; varEnv = Map.empty } (e :> Expr) + + Expression.Lambda(linqExpr, Expression.Parameter(typeof)) |> asExpr let CompileImpl (e: #Expr, eraseEquality) = - let ty = e.Type - let e = Expr.NewDelegate(GetFuncType([|typeof; ty |]), [new Var("unit",typeof)],e) +// let ty = e.Type +// let e = Expr.NewDelegate(GetFuncType([|typeof; ty |]), [new Var("unit",typeof)],e) let linqExpr = Conv (e,eraseEquality) let linqExpr = (linqExpr :?> LambdaExpression) let d = linqExpr.Compile() diff --git a/tests/FSharp.Quotations.Evaluator.Tests/FSharp.Quotations.Evaluator.Tests.fsproj b/tests/FSharp.Quotations.Evaluator.Tests/FSharp.Quotations.Evaluator.Tests.fsproj index 9732f64..4824e26 100644 --- a/tests/FSharp.Quotations.Evaluator.Tests/FSharp.Quotations.Evaluator.Tests.fsproj +++ b/tests/FSharp.Quotations.Evaluator.Tests/FSharp.Quotations.Evaluator.Tests.fsproj @@ -30,6 +30,7 @@ + true pdbonly diff --git a/tests/FSharp.Quotations.Evaluator.Tests/Performance.fs b/tests/FSharp.Quotations.Evaluator.Tests/Performance.fs index 237eb2e..3846d24 100644 --- a/tests/FSharp.Quotations.Evaluator.Tests/Performance.fs +++ b/tests/FSharp.Quotations.Evaluator.Tests/Performance.fs @@ -105,7 +105,7 @@ let timeFunction functionQuotation = viaLinqMs, directMs, timeAllowanceMultiplier * 0.75, timeAllowanceMultiplier, viaLinqMs / directMs) -[] +[] let ``[answerDoors](http://rosettacode.org/wiki/100_doors#F.23)`` () = let ToggleNth n (lst:bool array) = // Toggle every n'th door [(n-1) .. n .. 99] // For each appropriate door From afdce7c29a96372558f8998a8c43381fcf8efe46 Mon Sep 17 00:00:00 2001 From: Paul Westcott Date: Thu, 13 Nov 2014 05:11:27 +1100 Subject: [PATCH 19/26] Some expression tree rewriting for better compilation --- .../QuotationsEvaluator.fs | 65 +++++++++++++++++-- 1 file changed, 61 insertions(+), 4 deletions(-) diff --git a/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fs b/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fs index 584e476..28f64dd 100644 --- a/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fs +++ b/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fs @@ -476,10 +476,6 @@ module QuotationEvaluationTypes = exprConstructor(e1, e2, false, intrinsic.MakeGenericMethod([|x1.Type|])) |> asExpr match inp with - // Special cases for this translation - | PlusQ (_, [ty1;ty2;ty3],[x1;x2]) when (ty1 = typeof) && (ty2 = typeof) -> - ConvExpr env (<@@ System.String.Concat( [| %%x1 ; %%x2 |] : string array ) @@>) - | SpecificCall <@ LanguagePrimitives.GenericEquality @> (_, _,[x1;x2]) | SpecificCall <@ ( = ) @> (_,_,[x1;x2]) -> transComparison x1 x2 Expression.Equal Expression.Equal genericEqualityIntrinsic | SpecificCall <@ ( > ) @> (_,_,[x1;x2]) -> transComparison x1 x2 Expression.GreaterThan Expression.GreaterThan genericGreaterThanIntrinsic @@ -944,7 +940,68 @@ module QuotationEvaluationTypes = //printf "** Expression .Parameter(%a, %a)\n" output_any ty output_any nm; Expression.Parameter(v.Type, v.Name) + let (|Λ|_|) (``method``:MethodInfo) = function + | Patterns.Call (o, methodInfo, args) when methodInfo.IsGenericMethod && methodInfo.Name = ``method``.Name -> + let generic = methodInfo.GetGenericMethodDefinition() + if ``method`` = generic then + let genericArgs = methodInfo.GetGenericArguments () + Some (o, genericArgs, args) + else + None + | _ -> None + + let rec getMethodInfo = function + | Patterns.Call(_,``method``,_) -> ``method`` + | Patterns.Lambda(_,body) -> getMethodInfo body + | _ -> failwith "Unexpected Form" + + let getGenericMethodInfo functionExpression = + let methodInfo = getMethodInfo functionExpression + if not methodInfo.IsGenericMethod then + failwith "Logic error; expected only generic methods" + methodInfo.GetGenericMethodDefinition () + + let ``|>`` = getGenericMethodInfo <@ (|>) @> + let ``<|`` = getGenericMethodInfo <@ (<|) @> + let ``+`` = getGenericMethodInfo <@ (+) @> + let ``id`` = getGenericMethodInfo <@ id @> + + let (|TraverseExpr|_|) f = function + | ExprShape.ShapeCombination (o, exprlist) -> Some (ExprShape.RebuildShapeCombination (o, List.map f exprlist)) + | ExprShape.ShapeLambda (var, expr) -> Some (Expr.Lambda (var, f expr)) + | untouched -> Some untouched + + let rec constantReplacement var value = function + | Patterns.Var v when v = var -> value + | TraverseExpr (constantReplacement var value) result -> result + | _ -> failwith "Invalid logic" + + let rec optimize = function + | Patterns.Let (var, binding, body) when not var.IsMutable -> + match optimize binding with + | (Patterns.Value _) as value -> optimize <| constantReplacement var value body + | optimizedBinding -> Expr.Let (var, optimizedBinding, optimize body) + | Patterns.Application (Lambda(var, body), input) -> optimize <| Expr.Let (var, input, body) + | Λ ``|>`` (None, _, [x1;x2]) -> optimize <| Expr.Application (x2, x1) + | Λ ``<|`` (None, _, [x1;x2]) -> optimize <| Expr.Application (x1, x2) + | Λ ``+`` (None, [|t1;_;_|], [x1;x2]) when t1 = typeof -> + let rec getStrings strings = function + | Λ ``+`` (None, [|t1;_;_|], [x1;x2]) when t1 = typeof -> getStrings (x2::strings) (x1) + | remainder -> remainder :: strings + let concat = + match getStrings [x2] (x1) with + | s1::s2::[] -> <@@ String.Concat(%%s1, %%s2) @@> + | s1::s2::s3::[] -> <@@ String.Concat(%%s1, %%s2, %%s3) @@> + | s1::s2::s3::s4::[] -> <@@ String.Concat(%%s1, %%s2, %%s3, %%s4) @@> + | strings -> Expr.Call (getMethodInfo <@ String.Concat ([||]:array) @>, [Expr.NewArray (typeof, strings)]) + optimize <| concat + | Λ ``id`` (None, _, [x1]) -> optimize x1 + | TraverseExpr optimize result -> result + | _ -> failwith "Invalid logic" + let Conv (e: #Expr,eraseEquality) = + let e = optimize e + let linqExpr = ConvExpr { eraseEquality = eraseEquality; varEnv = Map.empty } (e :> Expr) Expression.Lambda(linqExpr, Expression.Parameter(typeof)) |> asExpr From 6a48b19f9072d750740406718ed62f01e614a307 Mon Sep 17 00:00:00 2001 From: Paul Westcott Date: Thu, 13 Nov 2014 05:40:27 +1100 Subject: [PATCH 20/26] Changed TryFinally to use Expression.TryFinally --- src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fs | 7 +++---- .../FSharp.Quotations.Evaluator.Tests.fsproj | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fs b/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fs index 28f64dd..c794fc7 100644 --- a/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fs +++ b/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fs @@ -834,10 +834,9 @@ module QuotationEvaluationTypes = linqStatements |> asExpr | Patterns.TryFinally(e,h) -> - let eP = ConvExpr env (Expr.Lambda(new Var("unitVar",typeof), e)) - let hP = ConvExpr env <@@ (fun () -> (%%h:unit)) @@> - let minfo = TryFinallyMethod.GetGenericMethodDefinition().MakeGenericMethod [| e.Type |] - Expression.Call(minfo,[| eP; hP |]) |> asExpr + let eP = ConvExpr env e + let hP = ConvExpr env h + Expression.TryFinally(eP, hP) |> asExpr | Patterns.TryWith(e,vf,filter,vh,handler) -> let eP = ConvExpr env (Expr.Lambda(new Var("unitVar",typeof), e)) diff --git a/tests/FSharp.Quotations.Evaluator.Tests/FSharp.Quotations.Evaluator.Tests.fsproj b/tests/FSharp.Quotations.Evaluator.Tests/FSharp.Quotations.Evaluator.Tests.fsproj index 4824e26..3cbd7fe 100644 --- a/tests/FSharp.Quotations.Evaluator.Tests/FSharp.Quotations.Evaluator.Tests.fsproj +++ b/tests/FSharp.Quotations.Evaluator.Tests/FSharp.Quotations.Evaluator.Tests.fsproj @@ -30,7 +30,7 @@ - true + false pdbonly From 1321419f7f560dc726c8af21f2b5057fa523e731 Mon Sep 17 00:00:00 2001 From: Paul Westcott Date: Thu, 13 Nov 2014 05:52:05 +1100 Subject: [PATCH 21/26] Added new Configuration for Performance In normal Release build the Performance tests are now Ignored. --- .../FSharp.Quotations.Evaluator.Tests.fsproj | 9 +++++++++ .../Performance.fs | 18 +++++++++++------- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/tests/FSharp.Quotations.Evaluator.Tests/FSharp.Quotations.Evaluator.Tests.fsproj b/tests/FSharp.Quotations.Evaluator.Tests/FSharp.Quotations.Evaluator.Tests.fsproj index 3cbd7fe..febe6d3 100644 --- a/tests/FSharp.Quotations.Evaluator.Tests/FSharp.Quotations.Evaluator.Tests.fsproj +++ b/tests/FSharp.Quotations.Evaluator.Tests/FSharp.Quotations.Evaluator.Tests.fsproj @@ -44,6 +44,15 @@ 11 + + pdbonly + true + true + TRACE;INCLUDE_TIMING_TESTS + 3 + bin\Release\FSharp.Quotations.Evaluator.Tests.xml + bin\Release\ + diff --git a/tests/FSharp.Quotations.Evaluator.Tests/Performance.fs b/tests/FSharp.Quotations.Evaluator.Tests/Performance.fs index 3846d24..16f50a1 100644 --- a/tests/FSharp.Quotations.Evaluator.Tests/Performance.fs +++ b/tests/FSharp.Quotations.Evaluator.Tests/Performance.fs @@ -57,6 +57,7 @@ let getTimeAllowanceMultiplier (``method``:MethodInfo) = then TimeAllowanceAttribute.DefaultMultiplier else timeAllowance.Multiplier +#if INCLUDE_TIMING_TESTS // we probably have a lot of ceremony here for no particular reason, but it shouldn't hurt let timeFunction functionQuotation = let ``method``, compiledMethod, directlyCallMethod = @@ -103,7 +104,10 @@ let timeFunction functionQuotation = Assert.GreaterOrEqual (viaLinqMs, allowedTime * 0.75, "Too fast; decrease the multiplier! linq={0:0} compiled={1:0} allowed multiples={2:0.00}-{3:0.00} actual multiples={4:0.00}", viaLinqMs, directMs, timeAllowanceMultiplier * 0.75, timeAllowanceMultiplier, viaLinqMs / directMs) - +#else +let timeFunction _ = + Assert.Ignore "Ignoring timing tests. Set INCLUDE_TIMING_TESTS" +#endif [] let ``[answerDoors](http://rosettacode.org/wiki/100_doors#F.23)`` () = @@ -139,7 +143,7 @@ let ``Time [answer2](http://rosettacode.org/wiki/100_doors#F.23)`` () = timeFunction <@ ``[answer2](http://rosettacode.org/wiki/100_doors#F.23)`` @> -[] +[] let ``[Euler_method](http://rosettacode.org/wiki/Euler_method#F.23)`` () = let euler f (h : float) t0 y0 = (t0, y0) @@ -379,7 +383,7 @@ let ``Time single Operators <>=`` () = timeFunction <@ ``single Operators <>=`` @> -[] +[] let ``float cast`` () = let rand = Random 3141592 let mutable total = 0.0 @@ -396,7 +400,7 @@ let ``Time float cast`` () = timeFunction <@ ``float cast`` @> -[] +[] let ``int64 cast`` () = let rand = Random 3141592 let mutable total = 0L @@ -413,7 +417,7 @@ let ``Time int64 cast`` () = timeFunction <@ ``int64 cast`` @> -[] +[] let ``id function`` () = let rand = Random 3141592 let mutable total = 0 @@ -430,7 +434,7 @@ let ``Time id function`` () = timeFunction <@ ``id function`` @> -[] +[] let ``operator |>`` () = let rand = Random 3141592 let mutable total = 0 @@ -447,7 +451,7 @@ let ``Time operator |>`` () = timeFunction <@ ``operator |>`` @> -[] +[] let ``operator <|`` () = let rand = Random 3141592 let mutable total = 0 From e6f9b7beed0ae2aa95790ff1617b5ff5eaa9d802 Mon Sep 17 00:00:00 2001 From: Paul Westcott Date: Thu, 13 Nov 2014 16:29:37 +1100 Subject: [PATCH 22/26] Removed DerivedPatterns.SpecificCall as it was _slow_ --- .../QuotationsEvaluator.fs | 273 ++++++++++-------- 1 file changed, 146 insertions(+), 127 deletions(-) diff --git a/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fs b/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fs index c794fc7..fdfe171 100644 --- a/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fs +++ b/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fs @@ -350,49 +350,93 @@ module QuotationEvaluationTypes = else e - let (|NotQ|_|) = (|SpecificCall|_|) <@ not @> - let (|NegQ|_|) = (|SpecificCall|_|) <@ ( ~-) : int -> int @> - let (|PlusQ|_|) = (|SpecificCall|_|) <@ ( + ) @> - let (|DivideQ|_|) = (|SpecificCall|_|) <@ ( / ) @> - let (|MinusQ|_|) = (|SpecificCall|_|) <@ ( - ) @> - let (|MultiplyQ|_|) = (|SpecificCall|_|) <@ ( * ) @> - let (|ModuloQ|_|) = (|SpecificCall|_|) <@ ( % ) @> - let (|ShiftLeftQ|_|) = (|SpecificCall|_|) <@ ( <<< ) @> - let (|ShiftRightQ|_|) = (|SpecificCall|_|) <@ ( >>> ) @> - let (|BitwiseAndQ|_|) = (|SpecificCall|_|) <@ ( &&& ) @> - let (|BitwiseOrQ|_|) = (|SpecificCall|_|) <@ ( ||| ) @> - let (|BitwiseXorQ|_|) = (|SpecificCall|_|) <@ ( ^^^ ) @> - let (|BitwiseNotQ|_|) = (|SpecificCall|_|) <@ ( ~~~ ) @> - let (|CheckedNeg|_|) = (|SpecificCall|_|) <@ Checked.( ~-) : int -> int @> - let (|CheckedPlusQ|_|) = (|SpecificCall|_|) <@ Checked.( + ) @> - let (|CheckedMinusQ|_|) = (|SpecificCall|_|) <@ Checked.( - ) @> - let (|CheckedMultiplyQ|_|) = (|SpecificCall|_|) <@ Checked.( * ) @> - let (|ConvCharQ|_|) = (|SpecificCall|_|) <@ char @> - let (|ConvDecimalQ|_|) = (|SpecificCall|_|) <@ decimal @> - let (|ConvFloatQ|_|) = (|SpecificCall|_|) <@ float @> - let (|ConvFloat32Q|_|) = (|SpecificCall|_|) <@ float32 @> - let (|ConvSByteQ|_|) = (|SpecificCall|_|) <@ sbyte @> - let (|ConvInt16Q|_|) = (|SpecificCall|_|) <@ int16 @> - let (|ConvInt32Q|_|) = (|SpecificCall|_|) <@ int32 @> - let (|ConvIntQ|_|) = (|SpecificCall|_|) <@ int @> - let (|ConvInt64Q|_|) = (|SpecificCall|_|) <@ int64 @> - let (|ConvByteQ|_|) = (|SpecificCall|_|) <@ byte @> - let (|ConvUInt16Q|_|) = (|SpecificCall|_|) <@ uint16 @> - let (|ConvUInt32Q|_|) = (|SpecificCall|_|) <@ uint32 @> - let (|ConvUInt64Q|_|) = (|SpecificCall|_|) <@ uint64 @> - - let (|CheckedConvCharQ|_|) = (|SpecificCall|_|) <@ Checked.char @> - let (|CheckedConvSByteQ|_|) = (|SpecificCall|_|) <@ Checked.sbyte @> - let (|CheckedConvInt16Q|_|) = (|SpecificCall|_|) <@ Checked.int16 @> - let (|CheckedConvInt32Q|_|) = (|SpecificCall|_|) <@ Checked.int32 @> - let (|CheckedConvInt64Q|_|) = (|SpecificCall|_|) <@ Checked.int64 @> - let (|CheckedConvByteQ|_|) = (|SpecificCall|_|) <@ Checked.byte @> - let (|CheckedConvUInt16Q|_|) = (|SpecificCall|_|) <@ Checked.uint16 @> - let (|CheckedConvUInt32Q|_|) = (|SpecificCall|_|) <@ Checked.uint32 @> - let (|CheckedConvUInt64Q|_|) = (|SpecificCall|_|) <@ Checked.uint64 @> - let (|LinqExpressionHelperQ|_|) = (|SpecificCall|_|) <@ LinqExpressionHelper @> - let (|ArrayLookupQ|_|) = (|SpecificCall|_|) <@ LanguagePrimitives.IntrinsicFunctions.GetArray : int[] -> int -> int @> - let (|ArrayAssignQ|_|) = (|SpecificCall|_|) <@ LanguagePrimitives.IntrinsicFunctions.SetArray : int[] -> int -> int -> unit @> + let (|Λ|_|) (``method``:MethodInfo) = function + | Patterns.Call (o, methodInfo, args) when methodInfo.Name = ``method``.Name -> + if methodInfo.IsGenericMethod then + let generic = methodInfo.GetGenericMethodDefinition() + if ``method`` = generic then + let genericArgs = methodInfo.GetGenericArguments () + Some (o, genericArgs, args) + else + None + elif ``method`` = methodInfo then + Some (o, [||], args) + else None + | _ -> None + + let rec getMethodInfo = function + | Patterns.Call(_,``method``,_) -> ``method`` + | Patterns.Lambda(_,body) -> getMethodInfo body + | _ -> failwith "Unexpected Form" + + let getGenericMethodInfo functionExpression = + let methodInfo = getMethodInfo functionExpression + if methodInfo.IsGenericMethod then + methodInfo.GetGenericMethodDefinition () + else + methodInfo + + let ``-> |>`` = getGenericMethodInfo <@ (|>) @> + let ``-> <|`` = getGenericMethodInfo <@ (<|) @> + let ``-> id`` = getGenericMethodInfo <@ id @> + let ``-> not`` = getGenericMethodInfo <@ not @> + + let ``-> generic=`` = getGenericMethodInfo <@ LanguagePrimitives.GenericEquality @> + let ``-> =`` = getGenericMethodInfo <@ ( = ) @> + let ``-> >`` = getGenericMethodInfo <@ ( > ) @> + let ``-> >=`` = getGenericMethodInfo <@ ( >= ) @> + let ``-> <`` = getGenericMethodInfo <@ ( < ) @> + let ``-> <=`` = getGenericMethodInfo <@ ( <= ) @> + let ``-> <>`` = getGenericMethodInfo <@ ( <> ) @> + + let ``-> ~-`` = getGenericMethodInfo <@ ( ~-) : int -> int @> + let ``-> +`` = getGenericMethodInfo <@ (+) @> + let ``-> /`` = getGenericMethodInfo <@ (/) @> + let ``-> -`` = getGenericMethodInfo <@ (-) @> + let ``-> *`` = getGenericMethodInfo <@ (*) @> + let ``-> %`` = getGenericMethodInfo <@ (%) @> + + let ``-> <<<`` = getGenericMethodInfo <@ (<<<) @> + let ``-> >>>`` = getGenericMethodInfo <@ (>>>) @> + let ``-> &&&`` = getGenericMethodInfo <@ (&&&) @> + let ``-> |||`` = getGenericMethodInfo <@ (|||) @> + let ``-> ^^^`` = getGenericMethodInfo <@ (^^^) @> + let ``-> ~~~`` = getGenericMethodInfo <@ (~~~) @> + + let ``-> checked~-`` = getGenericMethodInfo <@ Checked.(~-) : int -> int @> + let ``-> checked+`` = getGenericMethodInfo <@ Checked.(+) @> + let ``-> checked-`` = getGenericMethodInfo <@ Checked.(-) @> + let ``-> checked*`` = getGenericMethodInfo <@ Checked.(*) @> + + let ``-> char`` = getGenericMethodInfo <@ char @> + let ``-> decimal`` = getGenericMethodInfo <@ decimal @> + let ``-> float`` = getGenericMethodInfo <@ float @> + let ``-> float32`` = getGenericMethodInfo <@ float32 @> + let ``-> sbyte`` = getGenericMethodInfo <@ sbyte @> + let ``-> int16`` = getGenericMethodInfo <@ int16 @> + let ``-> int32`` = getGenericMethodInfo <@ int32 @> + let ``-> int`` = getGenericMethodInfo <@ int @> + let ``-> int64`` = getGenericMethodInfo <@ int64 @> + let ``-> byte`` = getGenericMethodInfo <@ byte @> + let ``-> uint16`` = getGenericMethodInfo <@ uint16 @> + let ``-> uint32`` = getGenericMethodInfo <@ uint32 @> + let ``-> uint64`` = getGenericMethodInfo <@ uint64 @> + + let ``-> checked.char`` = getGenericMethodInfo <@ Checked.char @> + let ``-> checked.sbyte`` = getGenericMethodInfo <@ Checked.sbyte @> + let ``-> checked.int16`` = getGenericMethodInfo <@ Checked.int16 @> + let ``-> checked.int32`` = getGenericMethodInfo <@ Checked.int32 @> + let ``-> checked.int64`` = getGenericMethodInfo <@ Checked.int64 @> + let ``-> checked.byte`` = getGenericMethodInfo <@ Checked.byte @> + let ``-> checked.uint16`` = getGenericMethodInfo <@ Checked.uint16 @> + let ``-> checked.uint32`` = getGenericMethodInfo <@ Checked.uint32 @> + let ``-> checked.uint64`` = getGenericMethodInfo <@ Checked.uint64 @> + + let ``-> linqExpressionHelper`` = getGenericMethodInfo <@ LinqExpressionHelper @> + + let ``-> getArray`` = getGenericMethodInfo <@ LanguagePrimitives.IntrinsicFunctions.GetArray : int[] -> int -> int @> + let ``-> setArray`` = getGenericMethodInfo <@ LanguagePrimitives.IntrinsicFunctions.SetArray : int[] -> int -> int -> unit @> + let (|ArrayTypeQ|_|) (ty:System.Type) = if ty.IsArray && ty.GetArrayRank() = 1 then Some(ty.GetElementType()) else None /// Convert F# quotations to LINQ expression trees. @@ -476,73 +520,74 @@ module QuotationEvaluationTypes = exprConstructor(e1, e2, false, intrinsic.MakeGenericMethod([|x1.Type|])) |> asExpr match inp with - | SpecificCall <@ LanguagePrimitives.GenericEquality @> (_, _,[x1;x2]) - | SpecificCall <@ ( = ) @> (_,_,[x1;x2]) -> transComparison x1 x2 Expression.Equal Expression.Equal genericEqualityIntrinsic - | SpecificCall <@ ( > ) @> (_,_,[x1;x2]) -> transComparison x1 x2 Expression.GreaterThan Expression.GreaterThan genericGreaterThanIntrinsic - | SpecificCall <@ ( >= ) @> (_,_,[x1;x2]) -> transComparison x1 x2 Expression.GreaterThanOrEqual Expression.GreaterThanOrEqual genericGreaterOrEqualIntrinsic - | SpecificCall <@ ( < ) @> (_,_,[x1;x2]) -> transComparison x1 x2 Expression.LessThan Expression.LessThan genericLessThanIntrinsic - | SpecificCall <@ ( <= ) @> (_,_,[x1;x2]) -> transComparison x1 x2 Expression.LessThanOrEqual Expression.LessThanOrEqual genericLessOrEqualIntrinsic - | SpecificCall <@ ( <> ) @> (_,_,[x1;x2]) -> transComparison x1 x2 Expression.NotEqual Expression.NotEqual genericNotEqualIntrinsic - - | NotQ (_, _,[x1]) -> Expression.Not(ConvExpr env x1) |> asExpr - - - | NegQ (_, _,[x1]) -> Expression.Negate(ConvExpr env x1) |> asExpr - | PlusQ (_, _,[x1;x2]) -> Expression.Add(ConvExpr env x1, ConvExpr env x2) |> asExpr - | DivideQ (_, _,[x1;x2]) -> Expression.Divide (ConvExpr env x1, ConvExpr env x2) |> asExpr - | MinusQ (_, _,[x1;x2]) -> Expression.Subtract(ConvExpr env x1, ConvExpr env x2) |> asExpr - | MultiplyQ (_, _,[x1;x2]) -> Expression.Multiply(ConvExpr env x1, ConvExpr env x2) |> asExpr - | ModuloQ (_, _,[x1;x2]) -> Expression.Modulo (ConvExpr env x1, ConvExpr env x2) |> asExpr +// | SpecificCall <@ ( .. ) @> (_,_,[x1;x2]) -> transComparison x1 x2 Expression.Equal Expression.Equal genericEqualityIntrinsic + + | Λ ``-> generic=`` (_,_,[x1;x2]) + | Λ ``-> =`` (_,_,[x1;x2]) -> transComparison x1 x2 Expression.Equal Expression.Equal genericEqualityIntrinsic + | Λ ``-> >`` (_,_,[x1;x2]) -> transComparison x1 x2 Expression.GreaterThan Expression.GreaterThan genericGreaterThanIntrinsic + | Λ ``-> >=`` (_,_,[x1;x2]) -> transComparison x1 x2 Expression.GreaterThanOrEqual Expression.GreaterThanOrEqual genericGreaterOrEqualIntrinsic + | Λ ``-> <`` (_,_,[x1;x2]) -> transComparison x1 x2 Expression.LessThan Expression.LessThan genericLessThanIntrinsic + | Λ ``-> <=`` (_,_,[x1;x2]) -> transComparison x1 x2 Expression.LessThanOrEqual Expression.LessThanOrEqual genericLessOrEqualIntrinsic + | Λ ``-> <>`` (_,_,[x1;x2]) -> transComparison x1 x2 Expression.NotEqual Expression.NotEqual genericNotEqualIntrinsic + + | Λ ``-> not`` (_,_,[x1]) -> Expression.Not(ConvExpr env x1) |> asExpr + | Λ ``-> ~-`` (_,_,[x1]) -> Expression.Negate(ConvExpr env x1) |> asExpr + | Λ ``-> +`` (_,_,[x1;x2]) -> Expression.Add(ConvExpr env x1, ConvExpr env x2) |> asExpr + | Λ ``-> /`` (_,_,[x1;x2]) -> Expression.Divide (ConvExpr env x1, ConvExpr env x2) |> asExpr + | Λ ``-> -`` (_,_,[x1;x2]) -> Expression.Subtract(ConvExpr env x1, ConvExpr env x2) |> asExpr + | Λ ``-> *`` (_,_,[x1;x2]) -> Expression.Multiply(ConvExpr env x1, ConvExpr env x2) |> asExpr + | Λ ``-> %`` (_,_,[x1;x2]) -> Expression.Modulo (ConvExpr env x1, ConvExpr env x2) |> asExpr /// REVIEW: basic arithmetic with method witnesses /// REVIEW: negate,add, divide, multiply, subtract with method witness - | ShiftLeftQ (_, _,[x1;x2]) -> Expression.LeftShift(ConvExpr env x1, ConvExpr env x2) |> asExpr - | ShiftRightQ (_, _,[x1;x2]) -> Expression.RightShift(ConvExpr env x1, ConvExpr env x2) |> asExpr - | BitwiseAndQ (_, _,[x1;x2]) -> Expression.And(ConvExpr env x1, ConvExpr env x2) |> asExpr - | BitwiseOrQ (_, _,[x1;x2]) -> Expression.Or(ConvExpr env x1, ConvExpr env x2) |> asExpr - | BitwiseXorQ (_, _,[x1;x2]) -> Expression.ExclusiveOr(ConvExpr env x1, ConvExpr env x2) |> asExpr - | BitwiseNotQ (_, _,[x1]) -> Expression.Not(ConvExpr env x1) |> asExpr + | Λ ``-> <<<`` (_,_,[x1;x2]) -> Expression.LeftShift(ConvExpr env x1, ConvExpr env x2) |> asExpr + | Λ ``-> >>>`` (_,_,[x1;x2]) -> Expression.RightShift(ConvExpr env x1, ConvExpr env x2) |> asExpr + | Λ ``-> &&&`` (_,_,[x1;x2]) -> Expression.And(ConvExpr env x1, ConvExpr env x2) |> asExpr + | Λ ``-> |||`` (_,_,[x1;x2]) -> Expression.Or(ConvExpr env x1, ConvExpr env x2) |> asExpr + | Λ ``-> ^^^`` (_,_,[x1;x2]) -> Expression.ExclusiveOr(ConvExpr env x1, ConvExpr env x2) |> asExpr + | Λ ``-> ~~~`` (_,_,[x1]) -> Expression.Not(ConvExpr env x1) |> asExpr /// REVIEW: bitwise operations with method witnesses - | CheckedNeg (_, _,[x1]) -> Expression.NegateChecked(ConvExpr env x1) |> asExpr - | CheckedPlusQ (_, _,[x1;x2]) -> Expression.AddChecked(ConvExpr env x1, ConvExpr env x2) |> asExpr - | CheckedMinusQ (_, _,[x1;x2]) -> Expression.SubtractChecked(ConvExpr env x1, ConvExpr env x2) |> asExpr - | CheckedMultiplyQ (_, _,[x1;x2]) -> Expression.MultiplyChecked(ConvExpr env x1, ConvExpr env x2) |> asExpr - - | ConvCharQ (_, [ty],[x1]) -> Expression.Convert(ConvExpr env x1, typeof) |> asExpr - | ConvDecimalQ (_, [ty],[x1]) -> Expression.Convert(ConvExpr env x1, typeof) |> asExpr - | ConvFloatQ (_, [ty],[x1]) -> Expression.Convert(ConvExpr env x1, typeof) |> asExpr - | ConvFloat32Q (_, [ty],[x1]) -> Expression.Convert(ConvExpr env x1, typeof) |> asExpr - | ConvSByteQ (_, [ty],[x1]) -> Expression.Convert(ConvExpr env x1, typeof) |> asExpr - | ConvInt16Q (_, [ty],[x1]) -> Expression.Convert(ConvExpr env x1, typeof) |> asExpr - | ConvInt32Q (_, [ty],[x1]) -> Expression.Convert(ConvExpr env x1, typeof) |> asExpr - | ConvIntQ (_, [ty],[x1]) -> Expression.Convert(ConvExpr env x1, typeof) |> asExpr - | ConvInt64Q (_, [ty],[x1]) -> Expression.Convert(ConvExpr env x1, typeof) |> asExpr - | ConvByteQ (_, [ty],[x1]) -> Expression.Convert(ConvExpr env x1, typeof) |> asExpr - | ConvUInt16Q (_, [ty],[x1]) -> Expression.Convert(ConvExpr env x1, typeof) |> asExpr - | ConvUInt32Q (_, [ty],[x1]) -> Expression.Convert(ConvExpr env x1, typeof) |> asExpr - | ConvUInt64Q (_, [ty],[x1]) -> Expression.Convert(ConvExpr env x1, typeof) |> asExpr + | Λ ``-> checked~-`` (_, _,[x1]) -> Expression.NegateChecked(ConvExpr env x1) |> asExpr + | Λ ``-> checked+`` (_, _,[x1;x2]) -> Expression.AddChecked(ConvExpr env x1, ConvExpr env x2) |> asExpr + | Λ ``-> checked-`` (_, _,[x1;x2]) -> Expression.SubtractChecked(ConvExpr env x1, ConvExpr env x2) |> asExpr + | Λ ``-> checked*`` (_, _,[x1;x2]) -> Expression.MultiplyChecked(ConvExpr env x1, ConvExpr env x2) |> asExpr + + | Λ ``-> char`` (_, [|ty|],[x1]) -> Expression.Convert(ConvExpr env x1, typeof) |> asExpr + | Λ ``-> decimal`` (_, [|ty|],[x1]) -> Expression.Convert(ConvExpr env x1, typeof) |> asExpr + | Λ ``-> float`` (_, [|ty|],[x1]) -> Expression.Convert(ConvExpr env x1, typeof) |> asExpr + | Λ ``-> float32`` (_, [|ty|],[x1]) -> Expression.Convert(ConvExpr env x1, typeof) |> asExpr + | Λ ``-> sbyte`` (_, [|ty|],[x1]) -> Expression.Convert(ConvExpr env x1, typeof) |> asExpr + | Λ ``-> int16`` (_, [|ty|],[x1]) -> Expression.Convert(ConvExpr env x1, typeof) |> asExpr + | Λ ``-> int32`` (_, [|ty|],[x1]) -> Expression.Convert(ConvExpr env x1, typeof) |> asExpr + | Λ ``-> int`` (_, [|ty|],[x1]) -> Expression.Convert(ConvExpr env x1, typeof) |> asExpr + | Λ ``-> int64`` (_, [|ty|],[x1]) -> Expression.Convert(ConvExpr env x1, typeof) |> asExpr + | Λ ``-> byte`` (_, [|ty|],[x1]) -> Expression.Convert(ConvExpr env x1, typeof) |> asExpr + | Λ ``-> uint16`` (_, [|ty|],[x1]) -> Expression.Convert(ConvExpr env x1, typeof) |> asExpr + | Λ ``-> uint32`` (_, [|ty|],[x1]) -> Expression.Convert(ConvExpr env x1, typeof) |> asExpr + | Λ ``-> uint64`` (_, [|ty|],[x1]) -> Expression.Convert(ConvExpr env x1, typeof) |> asExpr /// REVIEW: convert with method witness - | CheckedConvCharQ (_, [ty],[x1]) -> Expression.ConvertChecked(ConvExpr env x1, typeof) |> asExpr - | CheckedConvSByteQ (_, [ty],[x1]) -> Expression.ConvertChecked(ConvExpr env x1, typeof) |> asExpr - | CheckedConvInt16Q (_, [ty],[x1]) -> Expression.ConvertChecked(ConvExpr env x1, typeof) |> asExpr - | CheckedConvInt32Q (_, [ty],[x1]) -> Expression.ConvertChecked(ConvExpr env x1, typeof) |> asExpr - | CheckedConvInt64Q (_, [ty],[x1]) -> Expression.ConvertChecked(ConvExpr env x1, typeof) |> asExpr - | CheckedConvByteQ (_, [ty],[x1]) -> Expression.ConvertChecked(ConvExpr env x1, typeof) |> asExpr - | CheckedConvUInt16Q (_, [ty],[x1]) -> Expression.ConvertChecked(ConvExpr env x1, typeof) |> asExpr - | CheckedConvUInt32Q (_, [ty],[x1]) -> Expression.ConvertChecked(ConvExpr env x1, typeof) |> asExpr - | CheckedConvUInt64Q (_, [ty],[x1]) -> Expression.ConvertChecked(ConvExpr env x1, typeof) |> asExpr - | ArrayLookupQ (_, [ArrayTypeQ(elemTy);_;_],[x1;x2]) -> + | Λ ``-> checked.char`` (_, [|ty|],[x1]) -> Expression.ConvertChecked(ConvExpr env x1, typeof) |> asExpr + | Λ ``-> checked.sbyte`` (_, [|ty|],[x1]) -> Expression.ConvertChecked(ConvExpr env x1, typeof) |> asExpr + | Λ ``-> checked.int16`` (_, [|ty|],[x1]) -> Expression.ConvertChecked(ConvExpr env x1, typeof) |> asExpr + | Λ ``-> checked.int32`` (_, [|ty|],[x1]) -> Expression.ConvertChecked(ConvExpr env x1, typeof) |> asExpr + | Λ ``-> checked.int64`` (_, [|ty|],[x1]) -> Expression.ConvertChecked(ConvExpr env x1, typeof) |> asExpr + | Λ ``-> checked.byte`` (_, [|ty|],[x1]) -> Expression.ConvertChecked(ConvExpr env x1, typeof) |> asExpr + | Λ ``-> checked.uint16`` (_, [|ty|],[x1]) -> Expression.ConvertChecked(ConvExpr env x1, typeof) |> asExpr + | Λ ``-> checked.uint32`` (_, [|ty|],[x1]) -> Expression.ConvertChecked(ConvExpr env x1, typeof) |> asExpr + | Λ ``-> checked.uint64`` (_, [|ty|],[x1]) -> Expression.ConvertChecked(ConvExpr env x1, typeof) |> asExpr + + | Λ ``-> getArray`` (_, [|ArrayTypeQ(elemTy);_;_|],[x1;x2]) -> Expression.ArrayIndex(ConvExpr env x1, ConvExpr env x2) |> asExpr - | ArrayAssignQ (_, [ArrayTypeQ(elemTy);_;_],[arr;idx;elem]) -> + | Λ ``-> setArray`` (_, [|ArrayTypeQ(elemTy);_;_|],[arr;idx;elem]) -> let minfo = ArrayAssignMethod.GetGenericMethodDefinition().MakeGenericMethod [| elemTy;typeof |] Expression.Call(minfo,[| ConvExpr env arr; ConvExpr env idx; ConvExpr env elem |]) |> asExpr // Throw away markers inserted to satisfy C#'s design where they pass an argument // or type T to an argument expecting Expr. - | LinqExpressionHelperQ (_, [_],[x1]) -> ConvExpr env x1 + | Λ ``-> linqExpressionHelper`` (_, [|_|],[x1]) -> ConvExpr env x1 /// ArrayLength /// ListBind @@ -939,32 +984,6 @@ module QuotationEvaluationTypes = //printf "** Expression .Parameter(%a, %a)\n" output_any ty output_any nm; Expression.Parameter(v.Type, v.Name) - let (|Λ|_|) (``method``:MethodInfo) = function - | Patterns.Call (o, methodInfo, args) when methodInfo.IsGenericMethod && methodInfo.Name = ``method``.Name -> - let generic = methodInfo.GetGenericMethodDefinition() - if ``method`` = generic then - let genericArgs = methodInfo.GetGenericArguments () - Some (o, genericArgs, args) - else - None - | _ -> None - - let rec getMethodInfo = function - | Patterns.Call(_,``method``,_) -> ``method`` - | Patterns.Lambda(_,body) -> getMethodInfo body - | _ -> failwith "Unexpected Form" - - let getGenericMethodInfo functionExpression = - let methodInfo = getMethodInfo functionExpression - if not methodInfo.IsGenericMethod then - failwith "Logic error; expected only generic methods" - methodInfo.GetGenericMethodDefinition () - - let ``|>`` = getGenericMethodInfo <@ (|>) @> - let ``<|`` = getGenericMethodInfo <@ (<|) @> - let ``+`` = getGenericMethodInfo <@ (+) @> - let ``id`` = getGenericMethodInfo <@ id @> - let (|TraverseExpr|_|) f = function | ExprShape.ShapeCombination (o, exprlist) -> Some (ExprShape.RebuildShapeCombination (o, List.map f exprlist)) | ExprShape.ShapeLambda (var, expr) -> Some (Expr.Lambda (var, f expr)) @@ -981,11 +1000,11 @@ module QuotationEvaluationTypes = | (Patterns.Value _) as value -> optimize <| constantReplacement var value body | optimizedBinding -> Expr.Let (var, optimizedBinding, optimize body) | Patterns.Application (Lambda(var, body), input) -> optimize <| Expr.Let (var, input, body) - | Λ ``|>`` (None, _, [x1;x2]) -> optimize <| Expr.Application (x2, x1) - | Λ ``<|`` (None, _, [x1;x2]) -> optimize <| Expr.Application (x1, x2) - | Λ ``+`` (None, [|t1;_;_|], [x1;x2]) when t1 = typeof -> + | Λ ``-> |>`` (None, _, [x1;x2]) -> optimize <| Expr.Application (x2, x1) + | Λ ``-> <|`` (None, _, [x1;x2]) -> optimize <| Expr.Application (x1, x2) + | Λ ``-> +`` (None, [|t1;_;_|], [x1;x2]) when t1 = typeof -> let rec getStrings strings = function - | Λ ``+`` (None, [|t1;_;_|], [x1;x2]) when t1 = typeof -> getStrings (x2::strings) (x1) + | Λ ``-> +`` (None, [|t1;_;_|], [x1;x2]) when t1 = typeof -> getStrings (x2::strings) (x1) | remainder -> remainder :: strings let concat = match getStrings [x2] (x1) with @@ -994,7 +1013,7 @@ module QuotationEvaluationTypes = | s1::s2::s3::s4::[] -> <@@ String.Concat(%%s1, %%s2, %%s3, %%s4) @@> | strings -> Expr.Call (getMethodInfo <@ String.Concat ([||]:array) @>, [Expr.NewArray (typeof, strings)]) optimize <| concat - | Λ ``id`` (None, _, [x1]) -> optimize x1 + | Λ ``-> id`` (None, _, [x1]) -> optimize x1 | TraverseExpr optimize result -> result | _ -> failwith "Invalid logic" From fb4c03ad1a3da25eec1a8ade11f3a66b2e47974d Mon Sep 17 00:00:00 2001 From: Paul Westcott Date: Thu, 13 Nov 2014 20:00:26 +1100 Subject: [PATCH 23/26] Provided an optimized op_Range --- .../QuotationsEvaluator.fs | 88 ++++++++++++++++++- .../Performance.fs | 2 +- 2 files changed, 86 insertions(+), 4 deletions(-) diff --git a/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fs b/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fs index fdfe171..ea31ff8 100644 --- a/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fs +++ b/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fs @@ -19,6 +19,8 @@ open Microsoft.FSharp.Quotations open Microsoft.FSharp.Quotations.Patterns open Microsoft.FSharp.Quotations.DerivedPatterns + + module ExtraHashCompare = let GenericNotEqualIntrinsic<'T> (x:'T) (y:'T) : bool = not (Microsoft.FSharp.Core.LanguagePrimitives.HashCompare.GenericEqualityIntrinsic<'T> x y) @@ -376,9 +378,6 @@ module QuotationEvaluationTypes = else methodInfo - let ``-> |>`` = getGenericMethodInfo <@ (|>) @> - let ``-> <|`` = getGenericMethodInfo <@ (<|) @> - let ``-> id`` = getGenericMethodInfo <@ id @> let ``-> not`` = getGenericMethodInfo <@ not @> let ``-> generic=`` = getGenericMethodInfo <@ LanguagePrimitives.GenericEquality @> @@ -984,6 +983,84 @@ module QuotationEvaluationTypes = //printf "** Expression .Parameter(%a, %a)\n" output_any ty output_any nm; Expression.Parameter(v.Type, v.Name) + module ``Custom Enumerables`` = + let CurrentIsState preStartState (moveNext:Func<_,_>) = + let getEnumerator () = + let current = ref preStartState + { new IEnumerator<'a> with + member __.Dispose() = () + member __.Current : 'a = !current + member __.Current : obj = upcast (!current) + member __.MoveNext() = + match moveNext.Invoke (!current) with + | None -> false + | Some next -> current := next; true + member __.Reset() = current := preStartState } + + { new IEnumerable<'a> with + member __.GetEnumerator() = getEnumerator () + member __.GetEnumerator(): Collections.IEnumerator = upcast (getEnumerator ()) } + + let inline IsType<'a,'b> = typeof<'a> = typeof<'b> + + [] + type ``Custom Operators``<'a> private () = + static let one = + if IsType<'a, sbyte> then Expression.Constant 1y + elif IsType<'a, byte> then Expression.Constant 1uy + elif IsType<'a, int16> then Expression.Constant 1s + elif IsType<'a, uint16> then Expression.Constant 1us + elif IsType<'a, int32> then Expression.Constant 1 + elif IsType<'a, uint32> then Expression.Constant 1ul + elif IsType<'a, int64> then Expression.Constant 1L + elif IsType<'a, uint64> then Expression.Constant 1UL + elif IsType<'a, float32> then Expression.Constant 1.f + elif IsType<'a, float> then Expression.Constant 1. + elif IsType<'a, bigint> then Expression.Constant 1I + elif IsType<'a, decimal> then Expression.Constant 1M + else failwith <| sprintf "Don't support type %A" typeof<'a> + + static let optionType = typeof> + static let optionConstructor = optionType.GetConstructor [| typeof<'a> |] + + static let subtractOne = + let n = Expression.Parameter (typeof<'a>, "n") + let subtractOne = Expression.Lambda>( Expression.Subtract(n, one), n) + subtractOne.Compile() + + static let boundedIncrement = + let upper = Expression.Parameter (typeof<'a>, "upper") + let n = Expression.Parameter (typeof<'a>, "n") + + let next = Expression.Variable (typeof<'a>) + let innerIncrement = + Expression.Lambda( + Expression.Block( + [next], + [ Expression.Assign (next, Expression.Add(n, one)) :> Expression + Expression.Condition ( + Expression.LessThanOrEqual (next, upper), + Expression.New (optionConstructor, next), + Expression.Property (null, optionType, "None")) :> Expression ]), + n) + + let outerBounding = + Expression.Lambda>>> (innerIncrement, upper) + + outerBounding.Compile () + + static member (..) lower upper = + let preStartState = subtractOne.Invoke lower + let moveNext = boundedIncrement.Invoke upper + ``Custom Enumerables``.CurrentIsState preStartState moveNext + + let ``-> id`` = getGenericMethodInfo <@ id @> + let ``-> |>`` = getGenericMethodInfo <@ (|>) @> + let ``-> <|`` = getGenericMethodInfo <@ (<|) @> + let ``-> ..`` = getGenericMethodInfo <@ (..) @> + let ``-> .. ..`` = getGenericMethodInfo <@ (.. ..) @> + let ``-> Custom ..`` = getGenericMethodInfo <@ ``Custom Operators``.op_Range @> + let (|TraverseExpr|_|) f = function | ExprShape.ShapeCombination (o, exprlist) -> Some (ExprShape.RebuildShapeCombination (o, List.map f exprlist)) | ExprShape.ShapeLambda (var, expr) -> Some (Expr.Lambda (var, f expr)) @@ -1000,6 +1077,11 @@ module QuotationEvaluationTypes = | (Patterns.Value _) as value -> optimize <| constantReplacement var value body | optimizedBinding -> Expr.Let (var, optimizedBinding, optimize body) | Patterns.Application (Lambda(var, body), input) -> optimize <| Expr.Let (var, input, body) + | Λ ``-> ..`` (None, ``type``, args) -> + let customOperatorsType = typedefof<``Custom Operators``<_>> + let specificType = customOperatorsType.MakeGenericType ``type`` + let ``method`` = specificType.GetMethod ("op_Range", BindingFlags.NonPublic ||| BindingFlags.Static) + optimize <| Expr.Call (``method``, args) | Λ ``-> |>`` (None, _, [x1;x2]) -> optimize <| Expr.Application (x2, x1) | Λ ``-> <|`` (None, _, [x1;x2]) -> optimize <| Expr.Application (x1, x2) | Λ ``-> +`` (None, [|t1;_;_|], [x1;x2]) when t1 = typeof -> diff --git a/tests/FSharp.Quotations.Evaluator.Tests/Performance.fs b/tests/FSharp.Quotations.Evaluator.Tests/Performance.fs index 16f50a1..7c6f6b9 100644 --- a/tests/FSharp.Quotations.Evaluator.Tests/Performance.fs +++ b/tests/FSharp.Quotations.Evaluator.Tests/Performance.fs @@ -127,7 +127,7 @@ let ``Time [answerDoors](http://rosettacode.org/wiki/100_doors#F.23)`` () = timeFunction <@ ``[answerDoors](http://rosettacode.org/wiki/100_doors#F.23)`` @> -[] +[] let ``[answer2](http://rosettacode.org/wiki/100_doors#F.23)`` () = let PerfectSquare n = let sqrt = int(Math.Sqrt(float n)) From d39ae832bcef66a0b63dcbd205e4bc9d9849d086 Mon Sep 17 00:00:00 2001 From: Paul Westcott Date: Thu, 13 Nov 2014 20:59:21 +1100 Subject: [PATCH 24/26] Provided an optimized op_RangeStep --- .../QuotationsEvaluator.fs | 54 ++++++++++++------- .../Performance.fs | 2 +- 2 files changed, 35 insertions(+), 21 deletions(-) diff --git a/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fs b/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fs index ea31ff8..76a7593 100644 --- a/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fs +++ b/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fs @@ -1006,29 +1006,31 @@ module QuotationEvaluationTypes = [] type ``Custom Operators``<'a> private () = static let one = - if IsType<'a, sbyte> then Expression.Constant 1y - elif IsType<'a, byte> then Expression.Constant 1uy - elif IsType<'a, int16> then Expression.Constant 1s - elif IsType<'a, uint16> then Expression.Constant 1us - elif IsType<'a, int32> then Expression.Constant 1 - elif IsType<'a, uint32> then Expression.Constant 1ul - elif IsType<'a, int64> then Expression.Constant 1L - elif IsType<'a, uint64> then Expression.Constant 1UL - elif IsType<'a, float32> then Expression.Constant 1.f - elif IsType<'a, float> then Expression.Constant 1. - elif IsType<'a, bigint> then Expression.Constant 1I - elif IsType<'a, decimal> then Expression.Constant 1M + if IsType<'a, sbyte> then failwith "Not supported" + elif IsType<'a, byte> then failwith "Not supported" + elif IsType<'a, int16> then box 1s + elif IsType<'a, uint16> then box 1us + elif IsType<'a, int32> then box 1 + elif IsType<'a, uint32> then box 1ul + elif IsType<'a, int64> then box 1L + elif IsType<'a, uint64> then box 1UL + elif IsType<'a, float32> then box 1.f + elif IsType<'a, float> then box 1. + elif IsType<'a, bigint> then box 1I + elif IsType<'a, decimal> then box 1M else failwith <| sprintf "Don't support type %A" typeof<'a> static let optionType = typeof> static let optionConstructor = optionType.GetConstructor [| typeof<'a> |] - static let subtractOne = + static let subtract = let n = Expression.Parameter (typeof<'a>, "n") - let subtractOne = Expression.Lambda>( Expression.Subtract(n, one), n) + let amount = Expression.Parameter (typeof<'a>, "amount") + let subtractOne = Expression.Lambda>( Expression.Subtract(n, amount), n, amount) subtractOne.Compile() static let boundedIncrement = + let incr = Expression.Parameter (typeof<'a>, "incr") let upper = Expression.Parameter (typeof<'a>, "upper") let n = Expression.Parameter (typeof<'a>, "n") @@ -1037,7 +1039,7 @@ module QuotationEvaluationTypes = Expression.Lambda( Expression.Block( [next], - [ Expression.Assign (next, Expression.Add(n, one)) :> Expression + [ Expression.Assign (next, Expression.Add(n, incr)) :> Expression Expression.Condition ( Expression.LessThanOrEqual (next, upper), Expression.New (optionConstructor, next), @@ -1045,13 +1047,19 @@ module QuotationEvaluationTypes = n) let outerBounding = - Expression.Lambda>>> (innerIncrement, upper) + Expression.Lambda>>> (innerIncrement, incr, upper) outerBounding.Compile () static member (..) lower upper = - let preStartState = subtractOne.Invoke lower - let moveNext = boundedIncrement.Invoke upper + let one = one :?> 'a + let preStartState = subtract.Invoke (lower, one) + let moveNext = boundedIncrement.Invoke (one, upper) + ``Custom Enumerables``.CurrentIsState preStartState moveNext + + static member (.. ..) lower (incr:'a) upper = + let preStartState = subtract.Invoke (lower, incr) + let moveNext = boundedIncrement.Invoke (incr, upper) ``Custom Enumerables``.CurrentIsState preStartState moveNext let ``-> id`` = getGenericMethodInfo <@ id @> @@ -1060,6 +1068,7 @@ module QuotationEvaluationTypes = let ``-> ..`` = getGenericMethodInfo <@ (..) @> let ``-> .. ..`` = getGenericMethodInfo <@ (.. ..) @> let ``-> Custom ..`` = getGenericMethodInfo <@ ``Custom Operators``.op_Range @> + let ``-> Custom .. ..`` = getGenericMethodInfo <@ ``Custom Operators``.op_RangeStep @> let (|TraverseExpr|_|) f = function | ExprShape.ShapeCombination (o, exprlist) -> Some (ExprShape.RebuildShapeCombination (o, List.map f exprlist)) @@ -1077,10 +1086,15 @@ module QuotationEvaluationTypes = | (Patterns.Value _) as value -> optimize <| constantReplacement var value body | optimizedBinding -> Expr.Let (var, optimizedBinding, optimize body) | Patterns.Application (Lambda(var, body), input) -> optimize <| Expr.Let (var, input, body) - | Λ ``-> ..`` (None, ``type``, args) -> + | Λ ``-> ..`` (None, [|``type``|], args) when ``type`` <> typeof && ``type`` <> typeof -> let customOperatorsType = typedefof<``Custom Operators``<_>> let specificType = customOperatorsType.MakeGenericType ``type`` - let ``method`` = specificType.GetMethod ("op_Range", BindingFlags.NonPublic ||| BindingFlags.Static) + let ``method`` = specificType.GetMethod (``-> Custom ..``.Name, BindingFlags.NonPublic ||| BindingFlags.Static) + optimize <| Expr.Call (``method``, args) + | Λ ``-> .. ..`` (None, [|ty1;ty2|], args) when ty1 = ty2 && (ty1 <> typeof && ty1 <> typeof) -> + let customOperatorsType = typedefof<``Custom Operators``<_>> + let specificType = customOperatorsType.MakeGenericType ty1 + let ``method`` = specificType.GetMethod (``-> Custom .. ..``.Name, BindingFlags.NonPublic ||| BindingFlags.Static) optimize <| Expr.Call (``method``, args) | Λ ``-> |>`` (None, _, [x1;x2]) -> optimize <| Expr.Application (x2, x1) | Λ ``-> <|`` (None, _, [x1;x2]) -> optimize <| Expr.Application (x1, x2) diff --git a/tests/FSharp.Quotations.Evaluator.Tests/Performance.fs b/tests/FSharp.Quotations.Evaluator.Tests/Performance.fs index 7c6f6b9..11b091b 100644 --- a/tests/FSharp.Quotations.Evaluator.Tests/Performance.fs +++ b/tests/FSharp.Quotations.Evaluator.Tests/Performance.fs @@ -109,7 +109,7 @@ let timeFunction _ = Assert.Ignore "Ignoring timing tests. Set INCLUDE_TIMING_TESTS" #endif -[] +[] let ``[answerDoors](http://rosettacode.org/wiki/100_doors#F.23)`` () = let ToggleNth n (lst:bool array) = // Toggle every n'th door [(n-1) .. n .. 99] // For each appropriate door From 695ae476ccfaeab67bb2e25b79efaf80c102715b Mon Sep 17 00:00:00 2001 From: Paul Westcott Date: Fri, 14 Nov 2014 06:17:04 +1100 Subject: [PATCH 25/26] Simplified WrapVoid Just used a Expression.Block --- .../QuotationsEvaluator.fs | 42 ++++--------------- 1 file changed, 9 insertions(+), 33 deletions(-) diff --git a/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fs b/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fs index 76a7593..819110c 100644 --- a/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fs +++ b/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fs @@ -324,33 +324,12 @@ module QuotationEvaluationTypes = let showAll = BindingFlags.Public ||| BindingFlags.NonPublic - let WrapVoid b objOpt args (env: ConvEnv) (e:Expression) = - if b then - let frees (e:Expr) = e.GetFreeVars() - let addFrees e acc = List.foldBack Set.add (frees e |> Seq.toList) acc - let fvs = Option.foldBack addFrees objOpt (List.foldBack addFrees args Set.empty) |> Set.toArray - let fvsP = fvs |> Array.map (fun v -> (Map.find v env.varEnv :?> ParameterExpression)) - let fvtys = fvs |> Array.map (fun v -> v.Type) - - let dty = GetActionType fvtys - let e = Expression.Lambda(dty,e,fvsP) - let d = e.Compile() - - let argtys = Array.append fvtys [| dty |] - let delP = Expression.Parameter(dty, "del") - - let m = new System.Reflection.Emit.DynamicMethod("wrapper",typeof,argtys) - let ilg = m.GetILGenerator() - - ilg.Emit(OpCodes.Ldarg ,fvs.Length) - fvs |> Array.iteri (fun i _ -> ilg.Emit(OpCodes.Ldarg ,int16 i)) - ilg.EmitCall(OpCodes.Callvirt,dty.GetMethod("Invoke",instanceBindingFlags),null) - ilg.Emit(OpCodes.Ldnull) - ilg.Emit(OpCodes.Ret) - let args = Array.append (fvsP |> Array.map asExpr) [| (Expression.Constant(d) |> asExpr) |] - Expression.Call((null:Expression),(m:>MethodInfo),args) |> asExpr - else - e + let wrapVoid (e:#Expression) = + if e.Type <> typeof then e |> asExpr + else + Expression.Block( + e, + Expression.Constant(null, typeof)) |> asExpr let (|Λ|_|) (``method``:MethodInfo) = function | Patterns.Call (o, methodInfo, args) when methodInfo.Name = ``method``.Name -> @@ -505,7 +484,7 @@ module QuotationEvaluationTypes = let args = (args @ [v]) let argsP = ConvExprs env args let minfo = propInfo.GetSetMethod(true) - Expression.Call(ConvObjArg env objOpt None, minfo,argsP) |> asExpr |> WrapVoid (IsVoidType minfo.ReturnType) objOpt args env + Expression.Call(ConvObjArg env objOpt None, minfo,argsP) |> wrapVoid // Expr.(Call,Application) | Patterns.Call(objOpt,minfo,args) -> @@ -594,7 +573,7 @@ module QuotationEvaluationTypes = /// ElementInit | _ -> let argsP = ConvExprs env args - Expression.Call(ConvObjArg env objOpt None, minfo, argsP) |> asExpr |> WrapVoid (IsVoidType minfo.ReturnType) objOpt args env + Expression.Call(ConvObjArg env objOpt None, minfo, argsP) |> wrapVoid // f x1 x2 x3 x4 --> InvokeFast4 | Patterns.Application(Patterns.Application(Patterns.Application(Patterns.Application(f,arg1),arg2),arg3),arg4) -> @@ -840,10 +819,7 @@ module QuotationEvaluationTypes = Expression.Break breakLabel)), breakLabel) - let linqAsUnitType = - Expression.Block(linqLoop, ConvExpr env <@ () @>) - - linqAsUnitType |> asExpr + linqLoop |> wrapVoid | Patterns.ForIntegerRangeLoop(indexer, lowerValue, upperValue, iteration) -> let linqLowerValue = ConvExpr env lowerValue From 33b0f13d17c650927cadd59ee8b9f228eb52d53f Mon Sep 17 00:00:00 2001 From: Paul Westcott Date: Fri, 14 Nov 2014 19:39:08 +1100 Subject: [PATCH 26/26] Simplified op_Range and op_RangeStep implementations --- .../QuotationsEvaluator.fs | 119 ++++++++---------- .../Performance.fs | 25 +++- 2 files changed, 69 insertions(+), 75 deletions(-) diff --git a/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fs b/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fs index 819110c..68a3970 100644 --- a/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fs +++ b/src/FSharp.Quotations.Evaluator/QuotationsEvaluator.fs @@ -980,71 +980,58 @@ module QuotationEvaluationTypes = let inline IsType<'a,'b> = typeof<'a> = typeof<'b> [] - type ``Custom Operators``<'a> private () = - static let one = - if IsType<'a, sbyte> then failwith "Not supported" - elif IsType<'a, byte> then failwith "Not supported" - elif IsType<'a, int16> then box 1s - elif IsType<'a, uint16> then box 1us - elif IsType<'a, int32> then box 1 - elif IsType<'a, uint32> then box 1ul - elif IsType<'a, int64> then box 1L - elif IsType<'a, uint64> then box 1UL - elif IsType<'a, float32> then box 1.f - elif IsType<'a, float> then box 1. - elif IsType<'a, bigint> then box 1I - elif IsType<'a, decimal> then box 1M - else failwith <| sprintf "Don't support type %A" typeof<'a> - - static let optionType = typeof> - static let optionConstructor = optionType.GetConstructor [| typeof<'a> |] - - static let subtract = - let n = Expression.Parameter (typeof<'a>, "n") - let amount = Expression.Parameter (typeof<'a>, "amount") - let subtractOne = Expression.Lambda>( Expression.Subtract(n, amount), n, amount) - subtractOne.Compile() - - static let boundedIncrement = - let incr = Expression.Parameter (typeof<'a>, "incr") - let upper = Expression.Parameter (typeof<'a>, "upper") - let n = Expression.Parameter (typeof<'a>, "n") - - let next = Expression.Variable (typeof<'a>) - let innerIncrement = - Expression.Lambda( - Expression.Block( - [next], - [ Expression.Assign (next, Expression.Add(n, incr)) :> Expression - Expression.Condition ( - Expression.LessThanOrEqual (next, upper), - Expression.New (optionConstructor, next), - Expression.Property (null, optionType, "None")) :> Expression ]), - n) - - let outerBounding = - Expression.Lambda>>> (innerIncrement, incr, upper) - - outerBounding.Compile () - - static member (..) lower upper = - let one = one :?> 'a - let preStartState = subtract.Invoke (lower, one) - let moveNext = boundedIncrement.Invoke (one, upper) - ``Custom Enumerables``.CurrentIsState preStartState moveNext - - static member (.. ..) lower (incr:'a) upper = - let preStartState = subtract.Invoke (lower, incr) - let moveNext = boundedIncrement.Invoke (incr, upper) - ``Custom Enumerables``.CurrentIsState preStartState moveNext + type OpRange() = + static let methods = + typeof.GetMethods (BindingFlags.Static ||| BindingFlags.NonPublic) + |> Array.filter (fun ``method`` -> ``method``.Name = "op_Range") + |> Array.map (fun ``method`` -> ``method``.ReturnType.GetGenericArguments().[0], ``method``) + |> dict + + static member TypeProvided ``type`` = methods.ContainsKey ``type`` + static member GetMethod ``type`` = methods.[``type``] + + static member private (..) (lower, upper) : seq = { lower .. upper} + static member private (..) (lower, upper) : seq = { lower .. upper} + static member private (..) (lower, upper) : seq = { lower .. upper} + static member private (..) (lower, upper) : seq = { lower .. upper} + static member private (..) (lower, upper) : seq = { lower .. upper} + static member private (..) (lower, upper) : seq = { lower .. upper} + static member private (..) (lower, upper) : seq = { lower .. upper} + static member private (..) (lower, upper) : seq = { lower .. upper} + static member private (..) (lower, upper) : seq = { lower .. upper} + static member private (..) (lower, upper) : seq = { lower .. upper} + static member private (..) (lower, upper) : seq = { lower .. upper} + static member private (..) (lower, upper) : seq = { lower .. upper} + + [] + type OpRangeStep() = + static let methods = + typeof.GetMethods (BindingFlags.Static ||| BindingFlags.NonPublic) + |> Array.filter (fun ``method`` -> ``method``.Name = "op_RangeStep") + |> Array.map (fun ``method`` -> ``method``.ReturnType.GetGenericArguments().[0], ``method``) + |> dict + + static member TypeProvided ``type`` = methods.ContainsKey ``type`` + static member GetMethod ``type`` = methods.[``type``] + + static member private (.. ..) (lower, incr, upper) : seq = { lower .. incr .. upper} + static member private (.. ..) (lower, incr, upper) : seq = { lower .. incr .. upper} + static member private (.. ..) (lower, incr, upper) : seq = { lower .. incr .. upper} + static member private (.. ..) (lower, incr, upper) : seq = { lower .. incr .. upper} + static member private (.. ..) (lower, incr, upper) : seq = { lower .. incr .. upper} + static member private (.. ..) (lower, incr, upper) : seq = { lower .. incr .. upper} + static member private (.. ..) (lower, incr, upper) : seq = { lower .. incr .. upper} + static member private (.. ..) (lower, incr, upper) : seq = { lower .. incr .. upper} + static member private (.. ..) (lower, incr, upper) : seq = { lower .. incr .. upper} + static member private (.. ..) (lower, incr, upper) : seq = { lower .. incr .. upper} + static member private (.. ..) (lower, incr, upper) : seq = { lower .. incr .. upper} + static member private (.. ..) (lower, incr, upper) : seq = { lower .. incr .. upper} let ``-> id`` = getGenericMethodInfo <@ id @> let ``-> |>`` = getGenericMethodInfo <@ (|>) @> let ``-> <|`` = getGenericMethodInfo <@ (<|) @> let ``-> ..`` = getGenericMethodInfo <@ (..) @> let ``-> .. ..`` = getGenericMethodInfo <@ (.. ..) @> - let ``-> Custom ..`` = getGenericMethodInfo <@ ``Custom Operators``.op_Range @> - let ``-> Custom .. ..`` = getGenericMethodInfo <@ ``Custom Operators``.op_RangeStep @> let (|TraverseExpr|_|) f = function | ExprShape.ShapeCombination (o, exprlist) -> Some (ExprShape.RebuildShapeCombination (o, List.map f exprlist)) @@ -1061,19 +1048,11 @@ module QuotationEvaluationTypes = match optimize binding with | (Patterns.Value _) as value -> optimize <| constantReplacement var value body | optimizedBinding -> Expr.Let (var, optimizedBinding, optimize body) - | Patterns.Application (Lambda(var, body), input) -> optimize <| Expr.Let (var, input, body) - | Λ ``-> ..`` (None, [|``type``|], args) when ``type`` <> typeof && ``type`` <> typeof -> - let customOperatorsType = typedefof<``Custom Operators``<_>> - let specificType = customOperatorsType.MakeGenericType ``type`` - let ``method`` = specificType.GetMethod (``-> Custom ..``.Name, BindingFlags.NonPublic ||| BindingFlags.Static) - optimize <| Expr.Call (``method``, args) - | Λ ``-> .. ..`` (None, [|ty1;ty2|], args) when ty1 = ty2 && (ty1 <> typeof && ty1 <> typeof) -> - let customOperatorsType = typedefof<``Custom Operators``<_>> - let specificType = customOperatorsType.MakeGenericType ty1 - let ``method`` = specificType.GetMethod (``-> Custom .. ..``.Name, BindingFlags.NonPublic ||| BindingFlags.Static) - optimize <| Expr.Call (``method``, args) + | Λ ``-> ..`` (None, [|``type``|], args) when OpRange.TypeProvided ``type`` -> optimize <| Expr.Call (OpRange.GetMethod ``type``, args) + | Λ ``-> .. ..`` (None, [|ty1;ty2|], args) when ty1 = ty2 && OpRangeStep.TypeProvided ty1 -> optimize <| Expr.Call (OpRangeStep.GetMethod ty1, args) | Λ ``-> |>`` (None, _, [x1;x2]) -> optimize <| Expr.Application (x2, x1) | Λ ``-> <|`` (None, _, [x1;x2]) -> optimize <| Expr.Application (x1, x2) + | Patterns.Application (Lambda(var, body), input) -> optimize <| Expr.Let (var, input, body) | Λ ``-> +`` (None, [|t1;_;_|], [x1;x2]) when t1 = typeof -> let rec getStrings strings = function | Λ ``-> +`` (None, [|t1;_;_|], [x1;x2]) when t1 = typeof -> getStrings (x2::strings) (x1) diff --git a/tests/FSharp.Quotations.Evaluator.Tests/Performance.fs b/tests/FSharp.Quotations.Evaluator.Tests/Performance.fs index 11b091b..ee6f7b0 100644 --- a/tests/FSharp.Quotations.Evaluator.Tests/Performance.fs +++ b/tests/FSharp.Quotations.Evaluator.Tests/Performance.fs @@ -109,7 +109,7 @@ let timeFunction _ = Assert.Ignore "Ignoring timing tests. Set INCLUDE_TIMING_TESTS" #endif -[] +[] let ``[answerDoors](http://rosettacode.org/wiki/100_doors#F.23)`` () = let ToggleNth n (lst:bool array) = // Toggle every n'th door [(n-1) .. n .. 99] // For each appropriate door @@ -127,7 +127,7 @@ let ``Time [answerDoors](http://rosettacode.org/wiki/100_doors#F.23)`` () = timeFunction <@ ``[answerDoors](http://rosettacode.org/wiki/100_doors#F.23)`` @> -[] +[] let ``[answer2](http://rosettacode.org/wiki/100_doors#F.23)`` () = let PerfectSquare n = let sqrt = int(Math.Sqrt(float n)) @@ -143,7 +143,7 @@ let ``Time [answer2](http://rosettacode.org/wiki/100_doors#F.23)`` () = timeFunction <@ ``[answer2](http://rosettacode.org/wiki/100_doors#F.23)`` @> -[] +[] let ``[Euler_method](http://rosettacode.org/wiki/Euler_method#F.23)`` () = let euler f (h : float) t0 y0 = (t0, y0) @@ -434,7 +434,7 @@ let ``Time id function`` () = timeFunction <@ ``id function`` @> -[] +[] let ``operator |>`` () = let rand = Random 3141592 let mutable total = 0 @@ -451,7 +451,7 @@ let ``Time operator |>`` () = timeFunction <@ ``operator |>`` @> -[] +[] let ``operator <|`` () = let rand = Random 3141592 let mutable total = 0 @@ -467,6 +467,21 @@ let ``Test operator <|`` () = let ``Time operator <|`` () = timeFunction <@ ``operator <|`` @> +[] +let ``operator .. ..`` () = + let mutable n = 0.0 + for i in { 1 .. 3 .. 100000 } do + n <- float i + n + +[] +let ``Test operator .. ..`` () = + testFunction <@ ``operator .. ..`` @> + +[] +let ``Time operator .. ..`` () = + timeFunction <@ ``operator .. ..`` @> + (* [] let ``[]()`` () =