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

учитывая следующий тип

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. Почему это?


person robkuz    schedule 24.08.2016    source источник
comment
Что ж, на самом деле нет никаких гарантий для конкретной формы выражения, пока она действительна. Другими словами: почему вы ожидаете, что они будут идентичными?   -  person Fyodor Soikin    schedule 24.08.2016
comment
@FyodorSoikin просто потому, что их идентичность значительно облегчит проверку и оценку. Нет?   -  person robkuz    schedule 24.08.2016


Ответы (2)


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

Например, цитата <@@ 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

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

person mavnn    schedule 24.08.2016

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

Это из спецификации языка F#.

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

person Colin Bull    schedule 24.08.2016