为 "roughly" 相同的代码引用生成不同的表达式
Different Expressions being generated for "roughly" the same code quotation
给定以下类型
type Foo = { foo: string; bar: int };;
和下面的代码引用
<@fun v x -> { x with foo = v; bar = 99 } @>;;
这将导致
val it : Quotations.Expr<(string -> Foo -> Foo)> =
Lambda (v, Lambda (x, NewRecord (Foo, v, Value (99))))
这是意料之中的。还有下面的代码引用
<@fun v x -> { x with bar = v;foo = "foo" } @>;;
产生了预期的结果。
val it : Quotations.Expr<(int -> Foo -> Foo)> =
Lambda (v, Lambda (x, NewRecord (Foo, Value ("foo"), v)))
然而这(改变顺序和将值分配给第二个字段)
<@fun v x -> { x with bar = 66;foo = v } @>;;
产量
val it : Quotations.Expr<(string -> Foo -> Foo)> =
Lambda (v, Lambda (x, Let (bar, Value (66), NewRecord (Foo, v, bar))))
一个let
。但是代码中没有let
。这是为什么?
引用仅保证它们将生成具有正确行为的表达式,而不是任何特定形状。
例如,引用 <@@ 1 = 2 || 2 = 3 @@>
将生成一个包含 if
语句(即 if 1 = 2 then true else 2 = 3
)的表达式。
归一化结果表达式是一个很深的兔子洞,但您可以在这里看到一些基本的归一化器:https://github.com/mavnn/Algebra.Boolean/blob/master/Algebra.Boolean/Transforms.fs
具体来说,检查文件末尾的unbind
。
let unbind quote =
let rec findLet q =
match q with
| Let (var, value, body) ->
findLet (replaceVar var.Name value body)
| ShapeLambda (v, e) ->
Expr.Lambda(v, findLet e)
| ShapeVar v ->
Expr.Var v
| ShapeCombination (o, es) ->
RebuildShapeCombination(o, es |> List.map findLet)
and replaceVar name value q =
match q with
| Let (v, e, e') ->
if v.Name = name then
findLet (Expr.Let(v, e, e'))
else
Expr.Let(v, replaceVar name value e, replaceVar name value e')
| ShapeLambda (v, e) ->
Expr.Lambda(v, replaceVar name value e)
| ShapeVar v ->
if v.Name = name then
value
else
Expr.Var v
| ShapeCombination (o, es) ->
RebuildShapeCombination(o, es |> List.map (replaceVar name value))
findLet quote
至于为什么这些具体的表达方式不同?不知道,恐怕!
我相信您在这里看到的是对记录中的 with
语法进行去糖处理的特例。我认为这里发生的事情是使用 v 来捕获值以确保以正确的字段顺序评估表达式。因此,在这种情况下,引入了 let 绑定,因为传入的参数是正在使用的第二个值。
本文来自 F# language spec。
Primitive record constructions are an elaborated form in which the
fields appear in the same order as in the record type definition.
Record expressions themselves elaborate to a form that may introduce
local value definitions to ensure that expressions are evaluated in
the same order that the field definitions appear in the original
expression
给定以下类型
type Foo = { foo: string; bar: int };;
和下面的代码引用
<@fun v x -> { x with foo = v; bar = 99 } @>;;
这将导致
val it : Quotations.Expr<(string -> Foo -> Foo)> =
Lambda (v, Lambda (x, NewRecord (Foo, v, Value (99))))
这是意料之中的。还有下面的代码引用
<@fun v x -> { x with bar = v;foo = "foo" } @>;;
产生了预期的结果。
val it : Quotations.Expr<(int -> Foo -> Foo)> =
Lambda (v, Lambda (x, NewRecord (Foo, Value ("foo"), v)))
然而这(改变顺序和将值分配给第二个字段)
<@fun v x -> { x with bar = 66;foo = v } @>;;
产量
val it : Quotations.Expr<(string -> Foo -> Foo)> =
Lambda (v, Lambda (x, Let (bar, Value (66), NewRecord (Foo, v, bar))))
一个let
。但是代码中没有let
。这是为什么?
引用仅保证它们将生成具有正确行为的表达式,而不是任何特定形状。
例如,引用 <@@ 1 = 2 || 2 = 3 @@>
将生成一个包含 if
语句(即 if 1 = 2 then true else 2 = 3
)的表达式。
归一化结果表达式是一个很深的兔子洞,但您可以在这里看到一些基本的归一化器:https://github.com/mavnn/Algebra.Boolean/blob/master/Algebra.Boolean/Transforms.fs
具体来说,检查文件末尾的unbind
。
let unbind quote =
let rec findLet q =
match q with
| Let (var, value, body) ->
findLet (replaceVar var.Name value body)
| ShapeLambda (v, e) ->
Expr.Lambda(v, findLet e)
| ShapeVar v ->
Expr.Var v
| ShapeCombination (o, es) ->
RebuildShapeCombination(o, es |> List.map findLet)
and replaceVar name value q =
match q with
| Let (v, e, e') ->
if v.Name = name then
findLet (Expr.Let(v, e, e'))
else
Expr.Let(v, replaceVar name value e, replaceVar name value e')
| ShapeLambda (v, e) ->
Expr.Lambda(v, replaceVar name value e)
| ShapeVar v ->
if v.Name = name then
value
else
Expr.Var v
| ShapeCombination (o, es) ->
RebuildShapeCombination(o, es |> List.map (replaceVar name value))
findLet quote
至于为什么这些具体的表达方式不同?不知道,恐怕!
我相信您在这里看到的是对记录中的 with
语法进行去糖处理的特例。我认为这里发生的事情是使用 v 来捕获值以确保以正确的字段顺序评估表达式。因此,在这种情况下,引入了 let 绑定,因为传入的参数是正在使用的第二个值。
本文来自 F# language spec。
Primitive record constructions are an elaborated form in which the fields appear in the same order as in the record type definition. Record expressions themselves elaborate to a form that may introduce local value definitions to ensure that expressions are evaluated in the same order that the field definitions appear in the original expression