F # — Конвейер с заданными параметрами

#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 , что означает, что он не может определить правильную перегрузку. Как я вижу, у вас есть несколько вариантов:

  1. Используйте разные имена методов. Есть ли причина, по которой вы должны использовать Property для ссылки на несколько разных операций? Было бы намного хуже использовать StringProperty , IntProperty и т.д. для каждой перегрузки? В общем, перегрузка усложняет работу компилятора (и часто для людей-сопровождающих тоже). В любом случае, мне не нравится идея именования метода Property
  2. Используйте явные параметры типа на 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 @>
      
  3. Явно укажите тип EF.Property :

     entityInfo |> curry (EF.Property: Expr<_ -> string> * _ -> _) <@ fun z -> z.Path @>
      

Конечно, эти последние два варианта не очень лаконичны, поэтому они могут не соответствовать цели использования конвейерного стиля.

Комментарии:

1. Моей первой мыслью было присвоить им имена типа StringProperty и IntProperty , но я подумал, что это плохая практика, поскольку большинство людей, похоже, предпочитают перегрузки вместо этого, но это не так? — И, как вы говорите, последние два приведенных вами варианта — это не то, что я бы назвал мм … аккуратным; p

2. @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)