В F # что означает конвейер? - PullRequest
7 голосов
/ 01 февраля 2010

Я читал эту статью Томаса Петричека, и она упоминала конвейеризацию |>, как в приведенном примере:

> let nums = [1; 2; 3; 4; 5];;
val nums : list<int>

> let odds_plus_ten = 
        nums
        |> List.filter (fun n-> n%2 <> 0)
        |> List.map (add 10)
val odds_plus_ten : list<int> = [11; 13; 15];;

Что означает конвейер? Первоначально я думал, что это сродни тому, как команда процессора передается по конвейеру внутри ядра. Можете ли вы объяснить, что это такое и как это работает в контексте F #?

Спасибо, С наилучшими пожеланиями, Том.

Ответы [ 4 ]

14 голосов
/ 01 февраля 2010

В некоторых отношениях нет ничего особенного в конвейерной обработке;вместо записи f (g (h x)) вы можете написать x |> h |> g |> f, что не кажется очевидным улучшением.Однако следует помнить о двух моментах:

  1. Иногда порядок чтения лучше для конвейерной версии: «Возьмите x и отправьте его h, отправьте результат g, отправьте результатf "легче понять, чем" применить f к результату применения g к результату применения h к x ".
  2. Вывод типа часто работает намного лучше для конвейерной версии.Вероятно, это самая главная причина того, что конвейерная обработка так часто используется в F #.Поскольку вывод типа происходит слева направо, x |> Array.map (fun s -> s.Length) будет работать, когда x равен string[], но Array.map (fun s -> s.Length) x не будет;вам нужно сделать Array.map (fun (s:string) -> s.Length) x вместо.
11 голосов
/ 01 февраля 2010

Конвейерная передача означает передачу результатов одной функции в другую функцию. В приведенном вами примере «nums» передается List.Filter, затем отфильтрованные результаты передаются в List.Map.

Больше информации здесь: http://msdn.microsoft.com/en-us/magazine/cc164244.aspx#S6

3 голосов
/ 01 февраля 2010

Как уже упоминалось, конвейеризация больше похожа на конвейер оболочки UNIX. Это позволит вам записать некоторый ввод с последующими операциями, которые должны быть применены к нему, вместо обычных вызовов вложенных функций. В этом примере стандартный код F # будет выглядеть так:

let r = List.map (add 10) (List.filter (fun n-> n%2 <> 0) nums)

Обратите внимание, что входные данные nums глубоко вложены в выражение, и не просто увидеть, что они сначала фильтруются, а затем проецируются. Используя конвейеризацию, вы можете написать код по-разному, но это будет означать одно и то же.

Хитрость в том, что оператор конвейерной обработки принимает два параметра, используя инфиксную нотацию (например, x |> f). Параметр x будет передан в качестве последнего аргумента функции справа (f). Вы можете использовать конвейерную обработку с любыми функциями F #:

let sinOne = 1.0 |> sin

let add a b = a + b
let r = 10 |> add 5 // it doesn't always make code more readable :-)

Важным моментом в операторе конвейеризации F # является то, что он не является какой-либо специальной встроенной функцией языка. Это простой пользовательский оператор, который вы можете определить самостоятельно:

let (|>) x f = f x

// Thanks to operator associativity rules, the following:
let r = 1.0 |> sin |> sqrt
// ...means this:
let r = (1.0 |> sin) |> sqrt
2 голосов
/ 01 февраля 2010

Проверьте Конвейер в F # для объяснения.

(Если вы знакомы с командной строкой Unix и такими каналами, как

cat file1 | sort | head 

это похожая идея; результат предыдущего выражения становится аргументом следующей функции.)

...