development

Haskell 구성 (.) 대 F #의 파이프 전달 연산자 (|>)

big-blog 2020. 8. 27. 08:14
반응형

Haskell 구성 (.) 대 F #의 파이프 전달 연산자 (|>)


F #에서는 파이프 포워드 연산자를 사용하는 |>것이 매우 일반적입니다. 그러나 Haskell에서는 함수 구성, (.)사용되는 것을 본 적이 있습니다 . 나는 그들이 관련되어 있음을 이해 하지만 파이프 포워드가 Haskell에서 사용되지 않거나 다른 것입니까?


나는 약간 투기 적이다 ...

문화 : 나는 |>F # "문화"에서 중요한 연산자 라고 생각합니다 . 그리고 아마도 .Haskell의 경우 와 유사 합니다. F #에는 함수 구성 연산자가 <<있지만 F # 커뮤니티 는 Haskell 커뮤니티보다 포인트없는 스타일을사용하는 경향이 있다고 생각합니다 .

언어 차이 : 비교할 두 언어에 대해 충분히 알지 못하지만 let-bindings를 일반화하는 규칙은 이것에 영향을 미칠만큼 충분히 다를 수 있습니다. 예를 들어 F #에서 가끔

let f = exp

컴파일되지 않으며 명시적인 eta-conversion이 필요합니다.

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

컴파일 할 수 있습니다. 이것은 또한 사람들을 무점 / 구성 스타일에서 벗어나 파이프 라이닝 스타일로 유도합니다. 또한 F # 유형 추론에는 파이프 라이닝이 필요한 경우가 있으므로 알려진 유형이 왼쪽에 표시됩니다 ( 여기 참조 ).

(개인적으로는 포인트 프리 스타일을 읽을 수 없다고 생각하지만 익숙해지기 전까지는 새롭거나 다른 모든 것을 읽을 수 없다고 생각합니다.)

두 언어 모두 잠재적으로 실행 가능하다고 생각하며 역사 / 문화 / 사고가 각 커뮤니티가 다른 "유인 자"에 정착 한 이유를 정의 할 수 있습니다.


F #에서는 (|>)왼쪽에서 오른쪽 형식 검사가 중요하기 때문에 중요합니다. 예를 들면 :

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

일반적으로 유형 검사를 수행하지 않습니다. 유형을 xs알고 있더라도 유형 x검사기가 볼 때 람다 에 대한 인수 유형을 알 수 없으므로 해결 방법을 알지 못하기 때문 x.Value입니다.

대조적으로

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

xs유형 x이 알려진 유형으로 이어 지기 때문에 잘 작동합니다 .

.NET Framework와 같은 구문에 포함 된 이름 확인 때문에 왼쪽에서 오른쪽 형식 검사가 필요합니다 x.Value. Simon Peyton Jones는 Haskell에 비슷한 종류의 이름 확인을 추가하기위한 제안작성 했지만 대신 로컬 제약 조건을 사용하여 유형이 특정 작업을 지원하는지 여부를 추적 할 것을 제안합니다. 요구 사항 첫 번째 샘플에 따라서 x필요 Value속성이 될 때까지 이월 될 xs보였다 이러한 요구 사항이 해결 될 수있다. 그러나 이것은 유형 시스템을 복잡하게 만듭니다.


더 많은 추측, 이번에는 주로 Haskell 측에서 ...

($)의 뒤집기이며 (|>)포인트 프리 코드를 작성할 수 없을 때 자주 사용됩니다. 따라서 (|>)Haskell에서 사용되지 않는 주된 이유 는 그 자리가 이미 ($).

또한 약간의 F # 경험 을 살펴보면 OO (|>)Subject.Verb(Object)구조 와 비슷하기 때문에 F # 코드에서 매우 인기가 있다고 생각 합니다. F #은 원활한 기능 / OO 통합을 목표로하기 때문에 Subject |> Verb Object새로운 기능 프로그래머에게 매우 부드러운 전환입니다.

개인적으로 나도 왼쪽에서 오른쪽으로 생각하는 것을 좋아하기 때문에 (|>)Haskell에서 사용하지만 다른 사람들은 그렇게 생각하지 않습니다.


나는 우리가 헷갈리는 것 같아요. Haskell의 ( .)는 F # 의 ( )와 같습니다 >>. |>역 함수 응용 프로그램이며 Haskell의 ( $) 와 같은 F #의 ( ) 와 혼동하지 마십시오 .

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


|>Haskell에서 F #을 사용하려면 Data.Function 에서 &연산자입니다 ( base 4.8.0.0).


Haskell에서 왼쪽에서 오른쪽으로 구성

어떤 사람들은 Haskell에서도 왼쪽에서 오른쪽 (메시지 전달) 스타일을 사용합니다. 예를 들어 Hackage의 mps 라이브러리를 참조하십시오 . 예 :

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]

때때로 왼쪽에서 오른쪽으로 구성하는 것을 선호하는 좋은 이유가 있습니다. 평가 순서는 읽기 순서를 따릅니다.


나는 >>>에서 사용되는 것을 보았고 flip (.), 특히 왼쪽에서 오른쪽으로 가장 잘 이해되는 긴 체인에 대해 자주 사용합니다.

>>> is actually from Control.Arrow, and works on more than just functions.


Aside from style and culture, this boils down to optimizing the language design for either pure or impure code.

The |> operator is common in F# largely because it helps to hide two limitations that appear with predominantly-impure code:

  • Left-to-right type inference without structural subtypes.
  • The value restriction.

Note that the former limitation does not exist in OCaml because subtyping is structural instead of nominal, so the structural type is easily refined via unification as type inference progresses.

Haskell takes a different trade-off, choosing to focus on predominantly-pure code where these limitations can be lifted.


I think F#'s pipe forward operator (|>) should vs (&) in 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

If you dont like (&) operator, you can custom it like F# or Elixir :

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

Why infixl 1 |>? See the doc in Data-Function (&)

infixl = infix + left associativity

infixr = infix + right associativity


(.)

(.) means function composition. It means (f.g)(x) = f(g(x)) in Math.

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

it equals

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

or

// (2)
foo x = negate $ x * 3 

($) operator is also defind in Data-Function ($).

(.) is used for create Hight Order Function or closure in js. See example:


// (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]

Wow, Less (code) is better.


Compare |> and .

ghci> 5 |> factorial |> show

// equals

ghci> (show . factorial) 5 

// equals

ghci> show . factorial $ 5 

It is the different between left —> right and right —> left. ⊙﹏⊙|||

Humanization

|> and & is better than .

because

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

How to functional programming in object-oriented language?

please visit http://reactivex.io/

It support :

  • Java: RxJava
  • JavaScript: RxJS
  • C#: Rx.NET
  • C#(Unity): UniRx
  • Scala: RxScala
  • Clojure: RxClojure
  • C++: RxCpp
  • Lua: RxLua
  • Ruby: Rx.rb
  • Python: RxPY
  • Go: RxGo
  • Groovy: RxGroovy
  • JRuby: RxJRuby
  • Kotlin: RxKotlin
  • Swift: RxSwift
  • PHP: RxPHP
  • Elixir: reaxive
  • Dart: RxDart

This is my first day to try Haskell (after Rust and F#), and I was able to define F#'s |> operator:

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

and it seems to work:

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

main =     
    5 |> factorial |> print

I bet a Haskell expert can give you an even better solution.

참고URL : https://stackoverflow.com/questions/1457140/haskell-composition-vs-fs-pipe-forward-operator

반응형