#f#
#f#
Вопрос:
Возможно ли каким-либо образом использовать конвейер для передачи последнего аргумента метода с заданными параметрами?
Пример:
// Member to call
static member Property (expr:Expr<'a -> string>, cfg:EntityInfo<'a>) = cfg.Property expr
// My curry function
let curry f x y = f (x,y)
// My EntityInfo<FileUpload>
let entityInfo = EF.Entity<FileUpload> modelBuilder
Я хочу иметь возможность вызывать его как:
entityInfo |> curry EF.Property <@ fun z -> z.Path @>
вместо
EF.Property(<@ fun z -> z.Path @>, entityInfo)
Комментарии:
1. То, что у вас есть, выглядит хорошо на первый взгляд, разве это не работает? В чем ошибка?
2. @Brian, «Не удалось определить уникальную перегрузку для метода ‘Property’ на основе информации о типе до этого программного пункта. Доступные перегрузки показаны ниже (или в окне Списка ошибок). Может потребоваться аннотация типа.»
3. Ах, да, перегрузка, ошибка вывода типов. Я не думаю, что есть способ заставить его работать с этим синтаксисом для перегруженного метода.
Ответ №1:
Я считаю, что это упрощенная версия вашей проблемы (хотя вы исключаете слишком много кода, чтобы быть уверенным):
type T() = class end
type S =
static member Method(_:int, T) = 'c'
static member Method(_:string, T) = false
let curry f x y = f(x,y)
// won't work
T() |> curry S.Method 1
Как упоминает Брайан, перегрузка плохо сочетается с выводом типов. В частности, поскольку вывод типа в F # выполняется слева направо, компилятор не использует тот факт, что 1
является int
при попытке выполнить поиск элемента для S.Method
, что означает, что он не может определить правильную перегрузку. Как я вижу, у вас есть несколько вариантов:
- Используйте разные имена методов. Есть ли причина, по которой вы должны использовать
Property
для ссылки на несколько разных операций? Было бы намного хуже использоватьStringProperty
,IntProperty
и т.д. для каждой перегрузки? В общем, перегрузка усложняет работу компилятора (и часто для людей-сопровождающих тоже). В любом случае, мне не нравится идея именования методаProperty
… -
Используйте явные параметры типа на
curry
и укажите их. Например.let curry<'a,'b,'c> f (x:'a) (y:'b) : 'c = f(x,y) entityInfo |> curry<Expr<_ -> string>,_,_> EF.Property <@ fun z -> z.Path @>
-
Явно укажите тип
EF.Property
:entityInfo |> curry (EF.Property: Expr<_ -> string> * _ -> _) <@ fun z -> z.Path @>
Конечно, эти последние два варианта не очень лаконичны, поэтому они могут не соответствовать цели использования конвейерного стиля.
Комментарии:
1. Моей первой мыслью было присвоить им имена типа
StringProperty
иIntProperty
, но я подумал, что это плохая практика, поскольку большинство людей, похоже, предпочитают перегрузки вместо этого, но это не так? — И, как вы говорите, последние два приведенных вами варианта — это не то, что я бы назвал мм … аккуратным; p2. @ebb — это зависит… Люди обычно используют перегрузку, когда можно вызвать метод с подмножеством аргументов, а не с полным списком — при использовании C # 3 или ниже это имело смысл, но теперь, вероятно, лучше использовать необязательные параметры. Использование перегрузки, когда метод может принимать два совершенно разных типа, встречается реже, и я почти всегда стараюсь избегать этого в пользу использования более описательных имен. Это особенно верно при использовании F #, поскольку, как вы видели, перегрузка может привести к хаосу при выводе типов.
Ответ №2:
Это потому, что он считает информацию об объекте как член EF.Вместо метода curry следует использовать метод Propery
entityInfo |> curry (EF.Property) (<@ fun z -> z.Path @>)
Комментарии:
1. Это вызывает исключение: «Элемент или конструктор объекта ‘Property’, принимающий 2 аргумента, недоступен из этого расположения кода. Все доступные версии метода ‘Property’ принимают 2 аргумента.»
2. хм .. Теперь он выдает: «Не удалось определить уникальную перегрузку для метода ‘Property’ на основе информации о типе до этого программного момента. Доступные перегрузки показаны ниже (или в окне Списка ошибок). Может потребоваться аннотация типа » — однако перегрузка должна быть правильной.
3. Пожалуйста, выведите ошибку, которую вы получаете при перегрузке, которую он пытается выполнить
4. «Несоответствие ограничений типа. Тип EntityInfo<FileUpload> несовместим с типом Quotes.Expr<(‘a -> строка)> Тип ‘EntityInfo<FileUpload>’ несовместим с типом ‘Quotes.Expr<(‘a -> string)>'»
5. Да, он не интерпретировал FileUpload в предложении, вам следует выполнить следующее
let expr:Expr<FileUpload -> string> = <@ fun z -> z.Path @>
, а затем вызвать это:let _ = entityInfo |> curry (EF.Property) (expr)