Трубопроводы, композиция и каррирование

Мне кажется, что все это связано. В чем разница?

Ответ 1

  • Трубопровод используется для выполнения последовательности операций с некоторым значением (точно так же, как трубопроводы в Unix). Вход для каждой функции - это выход предыдущей функции. Очевидно, это требует, чтобы каждая функция принимала один аргумент.

  • Композиция (<</>>) похожа на то, что она вызывает две функции в последовательности (т.е. вывод первого - это вход ко второму), но он возвращает функцию вместо непосредственного вызова последовательность.

  • Currying создает новую функцию, применяя аргументы 1 к N-1 для функции N args

Итак, композиция и currying используются для создания функций, тогда как для вызова используется конвейер. Состав и карри отличаются друг от друга тем, как они создают новые функции (применяя args vs chaining).

Ответ 2

В дополнение к тому, что написал Даниил, существует очень тесное соответствие между трубопроводами (операторами |> и <|) и композицией функций (операторы >> и <<).

Когда вы используете конвейер для передачи некоторых данных в последовательность функций:

nums |> Seq.filter isOdd
     |> Seq.map square
     |> Seq.sum

... то это эквивалентно передаче ввода функции, полученной с использованием композиции функций:

let composed = 
     Seq.filter isOdd
  >> Seq.map square
  >> Seq.sum

composed nums

На практике это часто означает, что вы можете заменить объявление функции, которое использует конвейер в аргументе с составом функций (и использовать тот факт, что функции могут использоваться как значения). Вот пример:

// Explicit function declaration
foo (fun x -> x |> bar |> goo)

// Equivalent using function composition
foo (bar >> goo)