Композиция на Haskell (.) И оператор прямого канала F # (|>) - PullRequest
92 голосов
/ 22 сентября 2009

В F # использование оператора pipe-forward, |>, довольно распространено. Однако в Хаскеле я когда-либо видел только композицию функций, (.), которая используется. Я понимаю, что они связаны , но есть ли языковая причина, по которой конвейерный переход не используется в Haskell или это что-то еще?

Ответы [ 10 ]

82 голосов
/ 22 сентября 2009

В F # (|>) важно из-за проверки типов слева направо. Например:

List.map (fun x -> x.Value) xs

обычно не проверяет тип, потому что даже если известен тип xs, тип аргумента x для лямбды не известен в тот момент, когда типограф проверяет его, поэтому он не знает как решить x.Value.

В отличие от

xs |> List.map (fun x -> x.Value)

будет работать нормально, потому что тип xs приведет к известному типу x.

Проверка типов слева направо требуется из-за разрешения имен, используемых в таких конструкциях, как x.Value. Саймон Пейтон Джонс написал предложение о добавлении подобного рода разрешения имен в Haskell, но он предлагает использовать локальные ограничения, чтобы отслеживать, поддерживает ли тип определенную операцию или нет. Таким образом, в первом примере требование о том, что x необходимо свойство Value, будет перенесено до тех пор, пока не будет замечено xs, и это требование может быть выполнено. Это, однако, усложняет систему типов.

60 голосов
/ 22 сентября 2009

Я немного умозрительный ...

Культура : Я думаю, |> является важным оператором в F # "культуре", и, возможно, аналогично . для Haskell. В F # есть оператор композиции функций <<, но я думаю, что сообщество F # склонно использовать стиль без баллов меньше, чем сообщество Haskell.

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

let f = exp

не скомпилируется, и вам нужно явное eta-преобразование:

let f x = (exp) x   // or x |> exp

чтобы его скомпилировать. Это также отвлекает людей от стиля без очков / композиции и от стиля конвейеризации. Кроме того, вывод типа F # иногда требует конвейерной обработки, так что известный тип появляется слева (см. здесь ).

(Лично я считаю стиль без очков нечитаемым, но я полагаю, что каждая новая / другая вещь кажется нечитаемой, пока вы к ней не привыкнете.)

Я думаю, что оба потенциально жизнеспособны на любом языке, и история / культура / несчастный случай могут определить, почему каждое сообщество обосновалось в своем "аттракторе".

42 голосов
/ 22 сентября 2009

Больше предположений, на этот раз со стороны преимущественно Haskell ...

($) - это переворот (|>), и его использование довольно распространено, когда вы не можете писать бессмысленный код. Таким образом, главная причина того, что (|>) не используется в Haskell, состоит в том, что его место уже занято ($).

Кроме того, говоря немного из опыта F #, я думаю, что (|>) настолько популярен в коде F #, потому что он напоминает структуру Subject.Verb(Object) OO. Поскольку F # стремится к плавной интеграции функционала и ОО, Subject |> Verb Object является довольно плавным переходом для новых функциональных программистов.

Лично мне тоже нравится думать слева направо, поэтому я использую (|>) в Haskell, но я не думаю, что это делают многие другие люди.

30 голосов
/ 22 апреля 2011

Я думаю, что мы все путаем. Хаскелла (.) эквивалентно F # (>>). Не путать с F # (|>), который является просто инвертированным приложением функции и похож на Haskell ($) - в обратном порядке:

let (>>) f g x = g (f x)
let (|>) x f = f x

Я считаю, что программисты на Haskell часто используют $. Возможно, не так часто, как программисты на F # склонны использовать |>. С другой стороны, некоторые парни из F # используют >> до смешного: http://blogs.msdn.com/b/ashleyf/archive/2011/04/21/programming-is-pointless.aspx

21 голосов
/ 27 сентября 2015

Если вы хотите использовать F # |> в Haskell, тогда в Data.Function - оператор & (начиная с base 4.8.0.0).

16 голосов
/ 26 мая 2010

Композиция слева направо в Хаскеле

Некоторые люди используют стиль Haskell слева направо (передача сообщений). См., Например, библиотеку mps в Hackage. Пример:

euler_1 = ( [3,6..999] ++ [5,10..999] ).unique.sum

Я думаю, что этот стиль выглядит хорошо в некоторых ситуациях, но его сложнее читать (нужно знать библиотеку и все ее операторы, переопределенное значение (.) тоже мешает).

В состав Control.Category , входящей в базовый пакет, входят также операторы композиции слева направо и справа налево. Сравните >>> и <<< соответственно:

ghci> :m + Control.Category
ghci> let f = (+2) ; g = (*3) in map ($1) [f >>> g, f <<< g]
[9,5]

Есть веская причина иногда отдавать предпочтение композиции слева направо: порядок оценки следует за порядком чтения.

15 голосов
/ 02 октября 2009

Я видел, как >>> используется для flip (.), и я часто использую это сам, особенно для длинных цепей, которые лучше всего понимаются слева направо.

>>> на самом деле из Control.Arrow и работает не только над функциями.

13 голосов
/ 24 апреля 2011

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

Оператор |> распространен в F # в основном потому, что он помогает скрыть два ограничения, которые появляются с преимущественно нечистым кодом:

  • Вывод типа слева направо без структурных подтипов.
  • Значение ограничения.

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

Haskell принимает другой компромисс, решив сосредоточиться на преимущественно чистом коде, где эти ограничения могут быть сняты.

1 голос
/ 10 августа 2017

Это мой первый день, чтобы попробовать Haskell (после Rust и F #), и я смог определить оператор F # |>:

(|>) :: a -> (a -> b) -> b
(|>) x f = f x
infixl 0 |>

и похоже на работу:

factorial x =
  case x of
    1 -> 1
    _ -> x * factorial (x-1)

main =     
    5 |> factorial |> print

Бьюсь об заклад, эксперт Haskell может дать вам еще лучшее решение.

0 голосов
/ 15 мая 2019

я думаю Оператор прямого канала F # (|>) должен против ( & ) в haskell.

// pipe operator example in haskell

factorial :: (Eq a, Num a) =>  a -> a
factorial x =
  case x of
    1 -> 1
    _ -> x * factorial (x-1)

// terminal
ghic >> 5 & factorial & show

Если вам не нравится оператор (&), вы можете настроить его как F # или Elixir:

(|>) :: a -> (a -> b) -> b
(|>) x f = f x
infixl 1 |>
ghci>> 5 |> factorial |> show

Почему infixl 1 |>? См. Документ в Функция данных (&)

infixl = инфикс + левая ассоциативность

infixr = инфикс + правая ассоциативность


(.)

(.) означает состав функции. Это означает (f.g) (x) = f (g (x)) в математике.

foo = negate . (*3)
// ouput -3
ghci>> foo 1
// ouput -15
ghci>> foo 5

равно

// (1)
foo x = negate (x * 3) 

или

// (2)
foo x = negate $ x * 3 
Оператор

($) также определен в Функция данных ($) .

(.) используется для создания Hight Order Function или closure in js. Смотрите пример:


// (1) use lamda expression to create a Hight Order Function
ghci> map (\x -> negate (abs x)) [5,-3,-6,7,-3,2,-19,24]  
[-5,-3,-6,-7,-3,-2,-19,-24]


// (2) use . operator to create a Hight Order Function
ghci> map (negate . abs) [5,-3,-6,7,-3,2,-19,24]  
[-5,-3,-6,-7,-3,-2,-19,-24]

Ух ты, Меньше (код) лучше.


Сравните |> и .

ghci> 5 |> factorial |> show

// equals

ghci> (show . factorial) 5 

// equals

ghci> show . factorial $ 5 

Это разница между left —> right и right —> left. ⊙﹏⊙ |||

Гуманизация

|> и & лучше, чем .

потому что

ghci> sum (replicate 5 (max 6.7 8.9))

// equals

ghci> 8.9 & max 6.7 & replicate 5 & sum

// equals

ghci> 8.9 |> max 6.7 |> replicate 5 |> sum

// equals

ghci> (sum . replicate 5 . max 6.7) 8.9

// equals

ghci> sum . replicate 5 . max 6.7 $ 8.9

Как сделать функциональное программирование на объектно-ориентированном языке?

пожалуйста, посетите http://reactivex.io/

Поддержка:

  • Java: RxJava
  • JavaScript: RxJS
  • C #: Rx.NET
  • C # (Unity): UniRx
  • Scala: RxScala
  • Clojure: RxClojure
  • C ++: RxCpp
  • Lua: RxLua
  • Рубин: Rx.rb
  • Python: RxPY
  • Go: RxGo
  • Groovy: RxGroovy
  • JRuby: RxJRuby
  • Kotlin: RxKotlin
  • Swift: RxSwift
  • PHP: RxPHP
  • Эликсир: реаксив
  • Дарт: RxDart
...