我有f#中微積分工具箱的開頭。對於學習f#來說,最重要的是有一些有用的東西可以用在我想到的其他項目中。基本和不完整的代碼是在F#中比較代碼引用的平等失敗
namespace BradGoneSurfing.Symbolics
open Microsoft.FSharp.Quotations
open Microsoft.FSharp.Quotations.Patterns
open Microsoft.FSharp.Quotations.DerivedPatterns
open System
open Microsoft.FSharp.Reflection
open Microsoft.FSharp.Quotations
open FSharpx.Linq.QuotationEvaluation
open Microsoft.FSharp.Linq.RuntimeHelpers
module Calculus =
let rec der_impl param quotation =
let (|X|_|) input = if input = param then Some(X) else None
match quotation with
| SpecificCall <@ (*) @> (_,types,l::r::[]) ->
let dl = der_impl param l
let dr = der_impl param r
<@@ (%%dl:double) * (%%r:double) + (%%l:double) * (%%dr:double) @@>
| SpecificCall <@ Math.Sin @> (_,_types, arg::_) ->
let di = der_impl param arg
<@@ Math.Cos((%%arg:double)) @@>
| ExprShape.ShapeVar v ->
match v with
| X -> <@@ 1.0 @@>
| _ -> (Expr.Var v)
| ExprShape.ShapeLambda (v,expr) -> Expr.Lambda (v,der_impl param expr)
| ExprShape.ShapeCombination (o, exprs) -> ExprShape.RebuildShapeCombination (o,List.map (fun e -> der_impl param e) exprs)
let rec der expr =
match expr with
| Lambda(param, body) ->
Expr.Lambda(param, (der_impl param body))
| _ -> failwith "oops"
,我有一個NUnit的/ FSUnit測試證明我的代碼
namespace BradGoneSurfing.Symbolics.Test
open FsUnit
open NUnit.Framework
open Microsoft.FSharp.Quotations
open BradGoneSurfing.Symbolics.Calculus
open FSharpx.Linq.QuotationEvaluation
open System
open Microsoft.FSharp.Linq.RuntimeHelpers
[<TestFixture>]
type ``This is a test for symbolic derivatives``()=
[<Test>]
member x.``Derivative should work``()=
let e = <@ (fun (y:double) -> y * y) @>
let d = der e
let x = <@ fun (y:double) -> 1.0 * y + y * 1.0 @>
d |> should equal x
第一位的測試樣的作品,但沒有。結果說
Expected:
Lambda (y,
Call (None, op_Addition,
[Call (None, op_Multiply, [Value (1.0), y]),
Call (None, op_Multiply, [y, Value (1.0)])]))
But Was:
Lambda (y,
Call (None, op_Addition,
[Call (None, op_Multiply, [Value (1.0), y]),
Call (None, op_Multiply, [y, Value (1.0)])]))
現在我的眼睛這兩個是相同的,但它似乎不是。我猜我已經與Expr vs Expr <'t>做了某種混合,但我不確定。一些實現代碼是試驗和錯誤來編譯它。
任何想法是什麼微妙的錯誤可能在這裏?
更新與解決方案
@Jack是正確的,無功實現參考平等,使得它很難用標準的平等與檢查代碼的報價。出於測試目的,它「足夠正確」來比較字符串。爲了使這一美味,我創建了FsUnit/NUnit的自定義匹配如下
type EqualsAsString (e:obj)=
inherit NUnit.Framework.Constraints.Constraint()
let expected = e
override x.Matches(actual:obj)=
x.actual <- actual
x.actual.ToString() = expected.ToString()
override x.WriteDescriptionTo(writer)=
writer.WriteExpectedValue(expected)
override x.WriteActualValueTo(writer)=
writer.WriteActualValue(x.actual)
和FSUnit包裝
let equalExpr (x:Expr<'t>) = new EqualsAsString(x)
所以我可以做
d |> should equalExpr <@ fun y -> y * y @>
,並預期它會工作。
我想我只是比較ToString並做它。這僅用於測試,如果字符串匹配,那麼它可能是相同的表達式。 – bradgonesurfing 2013-03-11 18:39:49