Linq Expression.Add 错误但 (+) 在 F# 中确实有效
Linq Expression.Add error but (+) does work in F#
#r "nuget: DiffSharp.Core, 1.0.7-preview1873603133"
#r "nuget: DiffSharp.Backends.Reference, 1.0.7-preview1873603133"
#r "nuget: DiffSharp.Backends.Torch, 1.0.7-preview1873603133"
open DiffSharp
open DiffSharp.Util
let t3 = dsharp.tensor [[1.1; 2.2]; [1.1; 2.2]; [1.1; 2.2]]
1 + t3 //Does work!!
open System.Linq.Expressions
let addB = Expression.Parameter(typeof<int>, "b")
let addC = Expression.Parameter(typeof<Tensor>, "c")
Expression.Add(
addC,
addB
) //=> Throw exception...
(*
System.InvalidOperationException: The binary operator Add is not defined for the types 'DiffSharp.Tensor' and 'System.Int32'.
at System.Linq.Expressions.Expression.GetUserDefinedBinaryOperatorOrThrow(ExpressionType binaryType, String name, Expression left, Expression right, Boolean liftToNull)
at System.Linq.Expressions.Expression.Add(Expression left, Expression right, MethodInfo method)
at System.Linq.Expressions.Expression.Add(Expression left, Expression right)
at <StartupCode$FSI_0048>.$FSI_0048.main@()
Stopped due to error
*)
为什么1+t3合法但无法解析成Linq表达式?
我想知道,如果应用此 RFC,是否有助于解决此问题?
F# RFC FS-1043 - Extension members become available to solve operator trait constraints
@panagiotis
type TRIVIAL = {
orz: int
}
with
static member (+) (vl : TRIVIAL, vr : TRIVIAL) =
{
orz = vl.orz + vr.orz
}
static member (+) (vl : TRIVIAL, vr : int) =
{
orz = vl.orz + vr
}
static member (+) (vl : int, vr : TRIVIAL) =
{
orz = vl + vr.orz * 100
}
let addA = Expression.Parameter(typeof<TRIVIAL>, "a")
let addB = Expression.Parameter(typeof<int>, "b")
Expression.Add(
addB,
addA
)
但为什么这也有效?
根据@NetMage的评论,最后的解决方案就像下面的代码片段:
值静态成员部分:
type Value =
| Number of BigRational
| Approximation of Approximation
| ComplexInfinity
| PositiveInfinity
| NegativeInfinity
| Undefined
| RealVec of Vector<float>
| ComplexVec of Vector<complex>
| RealMat of Matrix<float>
| ComplexMat of Matrix<complex>
| DSTen of Tensor
with
static member (+) (vl : Value, vr : Value) =
match vl with
| Number vlv ->
match vr with
| Number vrv ->
Number (vlv * vrv)
| Approximation (Real vlv) ->
match vr with
| Approximation (Real vrv) ->
Approximation (Real (vlv + vrv))
| DSTen dt ->
DSTen (vlv + dt)
static member (*) (vl : Value, vr : float) =
match vl with
| Approximation (Real vlv) ->
Approximation (Real (vlv * vr))
static member (*) (vl : float, vr : Value) =
match vr with
| Approximation (Real vrv) ->
Approximation (Real (vl * vrv))
static member (+) (vl : Value, vr : float) =
match vl with
| Approximation (Real vlv) ->
Approximation (Real (vlv + vr))
static member (+) (vl : float, vr : Value) =
match vr with
| Approximation vrv ->
match vrv with
| Approximation.Real vrvv ->
Approximation (Real (vl + vrvv))
| DSTen dt ->
DSTen (vl + dt)
铸造部分:
let exprObj2ValueToInject =
ExprHelper.Quote<Func<obj, MathNet.Symbolics.Value>> (fun j ->
match j with
| :? Value -> (j :?> Value)
| _ when j.GetType() = typeof<float> ->
Value.Approximation (Approximation.Real (j :?> float))
| :? Vector<float> ->
Value.RealVec (j :?> Vector<float>)
| :? Matrix<float> ->
Value.RealMat (j :?> Matrix<float>)
| _ ->
failwithf "orz010: %s, %A" (j.GetType().FullName) j
)
:> Expression :?> LambdaExpression
调用部分:
let xsvv =
xsv
|> List.map (fun xsExp ->
let casted = Expression.Convert(xsExp, typeof<obj>) :> Expression
let ivk = Expression.Invoke(exprObj2ValueToInject, [|casted|])
ivk :> Expression
)
let vLambda = Expression.Invoke(exprBy2Lambda, xsvv)
无论传入什么,我都将值转换为对象并使用匹配来确定如何包装它。
#r "nuget: DiffSharp.Core, 1.0.7-preview1873603133"
#r "nuget: DiffSharp.Backends.Reference, 1.0.7-preview1873603133"
#r "nuget: DiffSharp.Backends.Torch, 1.0.7-preview1873603133"
open DiffSharp
open DiffSharp.Util
let t3 = dsharp.tensor [[1.1; 2.2]; [1.1; 2.2]; [1.1; 2.2]]
1 + t3 //Does work!!
open System.Linq.Expressions
let addB = Expression.Parameter(typeof<int>, "b")
let addC = Expression.Parameter(typeof<Tensor>, "c")
Expression.Add(
addC,
addB
) //=> Throw exception...
(*
System.InvalidOperationException: The binary operator Add is not defined for the types 'DiffSharp.Tensor' and 'System.Int32'.
at System.Linq.Expressions.Expression.GetUserDefinedBinaryOperatorOrThrow(ExpressionType binaryType, String name, Expression left, Expression right, Boolean liftToNull)
at System.Linq.Expressions.Expression.Add(Expression left, Expression right, MethodInfo method)
at System.Linq.Expressions.Expression.Add(Expression left, Expression right)
at <StartupCode$FSI_0048>.$FSI_0048.main@()
Stopped due to error
*)
为什么1+t3合法但无法解析成Linq表达式? 我想知道,如果应用此 RFC,是否有助于解决此问题? F# RFC FS-1043 - Extension members become available to solve operator trait constraints
@panagiotis
type TRIVIAL = {
orz: int
}
with
static member (+) (vl : TRIVIAL, vr : TRIVIAL) =
{
orz = vl.orz + vr.orz
}
static member (+) (vl : TRIVIAL, vr : int) =
{
orz = vl.orz + vr
}
static member (+) (vl : int, vr : TRIVIAL) =
{
orz = vl + vr.orz * 100
}
let addA = Expression.Parameter(typeof<TRIVIAL>, "a")
let addB = Expression.Parameter(typeof<int>, "b")
Expression.Add(
addB,
addA
)
但为什么这也有效?
根据@NetMage的评论,最后的解决方案就像下面的代码片段:
值静态成员部分:
type Value =
| Number of BigRational
| Approximation of Approximation
| ComplexInfinity
| PositiveInfinity
| NegativeInfinity
| Undefined
| RealVec of Vector<float>
| ComplexVec of Vector<complex>
| RealMat of Matrix<float>
| ComplexMat of Matrix<complex>
| DSTen of Tensor
with
static member (+) (vl : Value, vr : Value) =
match vl with
| Number vlv ->
match vr with
| Number vrv ->
Number (vlv * vrv)
| Approximation (Real vlv) ->
match vr with
| Approximation (Real vrv) ->
Approximation (Real (vlv + vrv))
| DSTen dt ->
DSTen (vlv + dt)
static member (*) (vl : Value, vr : float) =
match vl with
| Approximation (Real vlv) ->
Approximation (Real (vlv * vr))
static member (*) (vl : float, vr : Value) =
match vr with
| Approximation (Real vrv) ->
Approximation (Real (vl * vrv))
static member (+) (vl : Value, vr : float) =
match vl with
| Approximation (Real vlv) ->
Approximation (Real (vlv + vr))
static member (+) (vl : float, vr : Value) =
match vr with
| Approximation vrv ->
match vrv with
| Approximation.Real vrvv ->
Approximation (Real (vl + vrvv))
| DSTen dt ->
DSTen (vl + dt)
铸造部分:
let exprObj2ValueToInject =
ExprHelper.Quote<Func<obj, MathNet.Symbolics.Value>> (fun j ->
match j with
| :? Value -> (j :?> Value)
| _ when j.GetType() = typeof<float> ->
Value.Approximation (Approximation.Real (j :?> float))
| :? Vector<float> ->
Value.RealVec (j :?> Vector<float>)
| :? Matrix<float> ->
Value.RealMat (j :?> Matrix<float>)
| _ ->
failwithf "orz010: %s, %A" (j.GetType().FullName) j
)
:> Expression :?> LambdaExpression
调用部分:
let xsvv =
xsv
|> List.map (fun xsExp ->
let casted = Expression.Convert(xsExp, typeof<obj>) :> Expression
let ivk = Expression.Invoke(exprObj2ValueToInject, [|casted|])
ivk :> Expression
)
let vLambda = Expression.Invoke(exprBy2Lambda, xsvv)
无论传入什么,我都将值转换为对象并使用匹配来确定如何包装它。