2015-06-09 2 views
2

Если я запускаю первый пример из MSDN (https://msdn.microsoft.com/en-us/library/dd233212.aspx) в окне F # Interactive, я получаю ожидаемый результат:Когда привязки в кодовых цитатах заменяются их значениями?

fun (x:System.Int32) -> x + 1 
a + 1 
let f = fun (x:System.Int32) -> x + 10 in f 10 

Но если я запускаю его в главном из моей программы, все пусть привязки заменяются их постоянные значения:

[<EntryPoint>] 
let main argv = 

    let a = 2 

    // exprLambda has type "(int -> int)". 
    let exprLambda = <@ fun x -> x + 1 @> 
    // exprCall has type unit. 
    let exprCall = <@ a + 1 @> 

    println exprLambda 
    println exprCall 
    println <@@ let f x = x + 10 in f 10 @@> 

Результат:

fun (x:System.Int32) -> x + 1 
2 + 1 
let f = fun (x:System.Int32) -> x + 10 in f 10 

Является ли это нормальным или ошибка? Являются ли правила для этого документированы? Что я могу сделать, чтобы заставить его к ожидаемому результату?

Edit:
Этот ответ (https://stackoverflow.com/a/4945137/1872399) утверждает (Variables are automatically replaced with values if the variable is defined outside of the quotation)., но я не мог найти ни одного упоминания об этом в другом месте.

Edit 2: То, что я действительно хочу сделать
Этот код (https://gist.github.com/0x53A/8848b04c2250364a3c22) переходит в броской всех случаях и не с not implemented:parseQuotation:Value (Variable "ax1") (я ожидал, что идти в | Var(var) ->), поэтому не только постоянных известных в compile- время, но и функциональные параметры расширяются до их значений.

Edit 3:
Я побежал рабочую версию (https://gist.github.com/0x53A/53f45949db812bde5d97) под отладчиком, и, похоже, что один на самом деле ошибка: Котировка является {Call (None, op_Addition, [PropertyGet (None, a, []), Value (1)])} с a = Program.a, так что это, кажется, побочный эффект того, что привязки в модулях компилируются в свойства. Если я прав, возможно, я должен зарегистрировать doc-ошибку в Microsoft ...

+0

Как выглядит ваша реализация 'println'? В этом примере печатается имя переменных, обозначенное символом '| Var (var) -> printf "% s" var.Name'. Вместо этого вы заменяете значение. –

+0

@JeffMercado Это та же реализация. Я только перевел вызов println в main. Заполните: https://gist.github.com/0x53A/393517e955736ea7f4c5 –

+0

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

ответ

2

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

Так, например, следующее в порядке, так как переменная x определяется лямбда:

<@ fun x -> x @> 

Но если у вас есть что-то вроде следующего, это не имеет смысла, чтобы захватить переменной x, потому что не только функция возвращает, x больше не находится в области:

fun x -> <@ x @> 

Это же к ситуации вы описываете - привязки верхнего уровня становятся статическими членами модуля и поэтому те могут б e, но локальные переменные недоступны после того, как выражение оценивается, и поэтому они заменяются значениями.Таким образом, общие правила:

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

Есть определенные случаи, когда возможность захватить имя переменной будет полезна. Один пример, который я действительно хотел, чтобы быть в состоянии сделать это, чтобы люди пишут, например:

plot(years, GDP) 

Идея заключается в том, что функция plot бы получить цитату с именами переменных (которые затем могут быть использованы, например, для оси участка). На самом деле есть an F# 4.0 change proposal, который позволяет вам это делать.

+0

Благодарим вас за это объяснение и особенно за ссылку на изменение F # 4. Вначале меня смутил пример MSDN, потому что он никогда не упоминал нигде, что он имеет какое-либо отношение к области верхнего уровня/локальной области. Если у меня есть время, я попробую предварительный просмотр F # 4, чтобы узнать, разрешает ли это моя проблема. (Новый шаблон ValueWithName должен) –

Смежные вопросы