2016-08-24 7 views
4

дал следующий типРазличные выражения генерируются для «примерно» тот же код котировка

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

Ну, нет действительно никакой гарантии для особая форма выражения, если это действительно так.Другими словами: почему вы ожидаете, что они будут идентичны? –

+0

@FyodorSoikin хорошо просто потому, что они были идентичными, упростили бы проверку и оценку. Нет? – robkuz

ответ

4

Котировки гарантируют, что они будут генерировать выражения с правильным поведением, а не с определенной формой.

Например, котировка <@@ 1 = 2 || 2 = 3 @@> будет генерировать выражение, содержащее оператор if (то есть if 1 = 2 then true else 2 = 3).

Нормализация полученных выражений довольно глубоко кроличья нора, но вы можете увидеть некоторые основные normalisers здесь: 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 

Относительно того, почему эти конкретные выражения различны? Боюсь, я не знаю.

4

Я считаю, что то, что вы видите здесь, является частным случаем обезжиривания синтаксиса with на записях. Я думаю, что здесь происходит использование v для захвата значения, чтобы гарантировать, что выражения оцениваются в правильном порядке полей. Таким образом, в этом случае вводится привязка let, поскольку переданный параметр является вторым используемым значением.

Это F# language spec.

Примитивные конструкции записи являются разработанной формой, в которой поля отображаются в том же порядке, что и в определении типа записи. запись выражения сами разрабатывающая в форму, которая может ввести определения локального значений, чтобы гарантировать, что выражения вычисляются в те же порядка, что определения полей появляются в исходном выражения