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