Композиция Хаскелла (.) Против оператора прямой трубы F # (|>)

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

Ответ 1

Я немного размышляю...

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

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

let f = exp

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

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

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

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

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

Ответ 2

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

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

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

В отличие от

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

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

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

Ответ 3

Больше спекуляций, на этот раз с преобладающей стороны Хаскелла...

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

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

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

Ответ 4

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

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

Ответ 5

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

Ответ 6

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

Некоторые люди используют стиль слева направо (сообщение) в 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]

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

Ответ 7

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

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

Ответ 8

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

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

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

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

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

Ответ 9

Это мой первый день, чтобы попробовать 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 может дать вам еще лучшее решение.

Ответ 10

Я думаю, что оператор F # pipe ( |>) должен быть против (&) в 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 |>? Смотрите документ в Data-Function (&)

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

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


(.)

( .) означает состав функции. Это означает (fg) (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 

Оператор ( $) также определяется в Data-Function ($).

( .) используется для создания 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
  • С#: Rx.NET
  • С# (Unity): UniRx
  • Scala: RxScala
  • Clojure: RxClojure
  • C++: RxCpp
  • Луа: RxLua
  • Рубин: Rx.rb
  • Python: RxPY
  • Go: RxGo
  • Groovy: RxGroovy
  • JRuby: RxJRuby
  • Котлин: RxKotlin
  • Swift: RxSwift
  • PHP: RxPHP
  • Эликсир: реаксив
  • Дарт: RxDart