Именованные аргументы конструктора в типе с использованием F#

Рассмотрим следующий код:

type Test(a) =
  member o.A = a

let test = Test(a = cos 5.)
let test2 = Test(a = 5. |> cos) // ERROR
let test3 = Test(a = (5. |> cos))

Строка Test2 выдает ошибку:

Тип «bool» не поддерживает никаких операторов с именем «Cos».

а также

Значение или конструктор 'a' не определен

Я понимаю сообщение об ошибке, но интересно, это не ошибка?


person Oldrich Svec    schedule 10.01.2011    source источник


Ответы (2)


Синтаксический анализатор F# обрабатывает именованные аргументы как выражения проверки на равенство; более поздняя стадия компилятора декодирует их в именованные аргументы. Таким образом, это проблема приоритета, как описано @desco.

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

F(a = true)    // named param
F((a = true))  // compare local name 'a', then pass boolean as first arg

как способ устранения неоднозначности в редком случае, когда это необходимо.

person Brian    schedule 10.01.2011
comment
... и F(a = (a = true)) тоже возможно. Зато выглядит забавно :) - person Frank; 11.01.2011

думаю, это нормально, так как приоритет (|>) меньше, чем (=) выражение

Test(a = 5. |> cos) 

интерпретируется как

Test((a = 5.) |> cos) 

и правильно ли в этом случае сообщение об ошибке

person desco    schedule 10.01.2011
comment
Но я не думаю, что = здесь знак равенства, не так ли? Что здесь будет означать знак равенства?: Test(a = cos 5.). Я бы ожидал, что = будет как в let a = 5. |› cos и приоритет должен быть соответственно. Я ошибаюсь? - person Oldrich Svec; 10.01.2011
comment
x = y — это логическое выражение (как и a = 5.), а let x = value связывает значение. - person Frank; 10.01.2011
comment
= на верхнем уровне (непосредственно внутри скобок) интерпретируется как именованный параметр или назначение поля/свойства. В любом другом месте это рассматривается как проверка на равенство. - person Markus Jarderot; 10.01.2011
comment
MizardX: Итак, если это назначение поля/свойства, оно должно иметь приоритет назначения. Я прав? - person Oldrich Svec; 10.01.2011
comment
@MizardX: Да, но из-за приоритета = a = 5. |> cos преобразуется в cos (a = 5.), а не в a = (5. |> cos). - person Frank; 10.01.2011
comment
@Oldrich: = - это оператор привязки и сравнения, но не присваивание (что делается с помощью <-). let a = 5. |> cos действительно связывает результат с a, но Test(a = 5. |> cos) фактически сравнивает a с 5.0, а затем пытается применить функцию cos к логическому результату, что, очевидно, не имеет смысла. - person Mephane; 10.01.2011
comment
@Mephane: я не согласен. Как можно сравнивать с несуществующим? С моей точки зрения это привязка аналогично записям. Пример: введите Test = {a: float } let test = {a = 5. |› cos } - person Oldrich Svec; 10.01.2011
comment
@Oldrich Svec: Как можно сравнивать с несуществующим? Ну, вы не можете, и это именно то, что говорит вам компилятор: значение или конструктор 'a' не определен. - person Frank; 10.01.2011
comment
@Novox: Но я говорю о так называемых именованных аргументах. См. здесь: msdn.microsoft.com/en-us/library/dd233192.aspx - person Oldrich Svec; 10.01.2011
comment
@Oldrich Svec: Кажется, я знаю, о чем вы говорите ;) К настоящему времени несколько человек пояснили в приведенных выше комментариях, что с a = 5. |> cos вы делаете что-то другое и почему это так. Если вы хотите передать именованный параметр, в этом случае вы должны использовать круглые скобки. - person Frank; 10.01.2011
comment
@Novox: насколько я понимаю, a = cos 5. рассматривается как именованный аргумент, и поэтому именованный аргумент имеет приоритет над оператором равенства. a = 5. |› cos, с другой стороны, рассматривается как оператор равенства, и, таким образом, оператор равенства имеет приоритет над именованным аргументом. Я нахожу это непоследовательным и запутанным. Но, наверное, это единственный способ, как это может быть реализовано... - person Oldrich Svec; 10.01.2011