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


100

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


2
lihanseys 대답 상태 &하스켈의입니다 |>. 이 실에 깊숙이 묻혀서 발견하는 데 며칠이 걸렸습니다. 코드를 따르기 위해 자연스럽게 왼쪽에서 오른쪽으로 읽기 때문에 많이 사용합니다.
itmuckel

답변:


61

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

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

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

let f = exp

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

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

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

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

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


7
나는 문화적 차이에 동의합니다. 전통 하스켈을 사용합니다 .$사람들을 계속 사용할 수 있도록.
Amok

9
포인트 프리는 포인트 풀 (pointful)보다 가독성이 높고 때로는 적습니다. 나는 일반적으로 람다가 일을 복잡하게 만드는 것을 피하기 위해 맵 및 필터와 같은 함수에 대한 인수에서 사용합니다. 나는 때때로 최상위 기능에서도 그것을 사용하지만 덜 자주 그리고 그것이 간단한 경우에만 사용합니다.
Paul Johnson

2
나는 F #에 관한 한 문제에서 선택의 여지가 많지 않다는 의미에서 많은 문화를 보지 못합니다 (당신과 Ganesh가 언급 한 이유 때문에). 그래서 두 가지 모두 Haskell에서 실행 가능하다고 말하고 싶지만 F #은 확실히 파이프 라인 연산자를 사용하는 데 훨씬 더 적합합니다.
Kurt Schelfthout

2
예, 왼쪽에서 오른쪽으로 읽는 문화는 수학도 그렇게 가르쳐야합니다 ...
nicolas

1
@nicolas 왼쪽에서 오른쪽은 임의의 선택입니다. 오른쪽에서 왼쪽으로 익숙해 질 수 있습니다.
Martin Capodici

86

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보였다 이러한 요구 사항이 해결 될 수있다. 그러나 이것은 유형 시스템을 복잡하게 만듭니다.


1
흥미로운 점은 Haskell에서 (.)와 유사한 (<|) 연산자가 있고 데이터의 오른쪽에서 왼쪽 방향이 같은 것입니다. 그러나 그것에 대한 작업 유형 확인은 어떻게 될까요?
The_Ghost

7
(<|)는 실제로 Haskell의 ($)와 유사합니다. 왼쪽에서 오른쪽으로 유형 검사는 .Value와 같은 문제를 해결하는 데만 필요하므로 (<|)는 다른 시나리오에서 또는 명시 적 유형 주석을 사용하는 경우 제대로 작동합니다.
GS는 - 모니카에 사과

44

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

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

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

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


안녕 Nathan, "flip ($)"은 Haskell 플랫폼 어디에나 미리 정의되어 있습니까? "(|>)"이름은 이미 다른 의미로 Data.Sequence에 정의되어 있습니다. 아직 정의하지 않은 경우 무엇이라고 부르나요? 나는 "($>) = 플립 ($)"로가는 생각 해요
mattbh

2
@mattbh : Hoogle에서 찾을 수있는 것은 아닙니다. 나는 약 몰랐다 Data.Sequence.|>, 그러나 $>충돌이를 방지하기 위해 합리적인 보인다. 솔직히 잘 생긴 연산자가 너무 많기 때문에 |>둘 다 사용 하고 사례별로 충돌을 관리합니다. (또한 그냥 별명에 유혹 될 수 Data.Sequence.|>snoc)
나단 Shively - 샌더스에게

2
($)(|>)응용 프로그램이 아닙니다 구성된다. 두가 (당신이 (질문 노트로) 관련 그러나 그들은 동일하지 않습니다되어 fc있다 (Control.Arrow.>>>)기능).
Nathan Shively-Sanders 2011

11
|>실제로 F # 은 실제로 |다른 무엇보다 UNIX를 떠올리게 합니다.
Kevin Cantu 2011

3
|>F # 의 또 다른 이점은 Visual Studio의 IntelliSense에 대한 멋진 속성이 있다는 것입니다. 를 입력 |>하면 왼쪽의 값에 적용 할 수있는 함수 목록이 표시됩니다 .. 이는 객체 뒤에 입력 할 때 발생하는 것과 유사 합니다.
Kristopher Johnson

32

나는 우리가 헷갈리는 것 같아요. 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


2
당신이 말했듯이 그것은 Haskell의 $연산자 와 같습니다 -반대로, 당신은 또한 쉽게 정의 할 수 있습니다 : a |> b = flip ($)이것은 F #의 파이프 라인과 동등 하게됩니다. 예를 들어 당신은 할 수 있습니다[1..10] |> map f
vis

8
( .)는 ( )와 같고 <<( >>)는 역 구성입니다. 그것은 ( >> ) : ('T1 -> 'T2) -> ('T2 -> 'T3) -> 'T1 -> 'T3( << ) : ('T2 -> 'T3) -> ('T1 -> 'T2) -> 'T1 -> 'T3
Dobes Vandermeer

-1 : "우스꽝스러운 정도로 사용". (글쎄요,하지만 당신은 내 요점을 얻었습니다). F #의 F는 "기능적"을 의미하므로 함수 구성이 합법적입니다.
Florian F

1
확실히 나는 기능 구성이 합법적이라는 데 동의합니다. "일부 F # 녀석들"은 나 자신을 언급하고 있습니다! 내 자신의 블로그. : P
AshleyF

나는 생각하지 않는다 .동일합니다 >>. F #에 있는지 모르겠지만 <<Elm에서와 같이 동등한 것입니다.
Matt Joiner

28

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


하스켈에 대한 모든 이유는 선택 &을 통해 |>? 나는 기분이 |>훨씬 더 직관적이며, 또한 유닉스 파이프 연산자 생각 나게한다.
yeshengm

16

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]

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


좋아요, 그래서 (>>>)는 대체로 (|>)와 동일합니까?
Khanzor 2012

@Khanzor 정확히는 아닙니다. (|>)는 인수를 적용합니다. (>>>)는 대부분 함수 구성 (또는 유사한 것)입니다. 그런 다음 고 정성 차이가 있다고 가정합니다 (확인하지 않았습니다).
sastanin

15

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

>>> 실제로 Control.Arrow에서 왔으며 기능 이상의 기능을 수행합니다.


>>>에 정의되어 Control.Category있습니다.
Steven Shaw

13

스타일과 문화를 제외하고 이것은 순수하거나 불순한 코드에 대한 언어 디자인을 최적화하는 것으로 귀결됩니다.

|>연산자는 주로 불순한 코드에서 나타나는 두 가지 제한 사항을 숨기는 데 도움이되기 때문에 F #에서 일반적으로 사용됩니다.

  • 구조적 하위 유형이없는 왼쪽에서 오른쪽 유형 추론.
  • 값 제한입니다.

하위 유형은 명목이 아닌 구조적이므로 OCaml에는 전자 제한이 존재하지 않으므로 유형 추론이 진행됨에 따라 통합을 통해 구조 유형을 쉽게 다듬을 수 있습니다.

Haskell은 이러한 한계를 극복 할 수있는 대부분의 순수 코드에 초점을 맞추기 위해 다른 절충안을 취합니다.


8

F #의 파이프 포워드 연산자 ( |>)는 하스켈에서 ( & ) 와 비교해야 한다고 생각 합니다 .

// 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 = 중위 + 왼쪽 연관성

중위 자 = 중위 + 오른쪽 연관성


(.)

( .)는 기능 구성을 의미합니다. 그 의미 (FG) (X) =를 (g (x)는 F) 연산이다.

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]

와, Less (코드)가 더 좋습니다.


비교 |>하고.

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/ 를 방문하십시오

IT 지원 :

  • 자바 : RxJava
  • 자바 스크립트 : RxJS
  • C # : Rx.NET
  • C # (Unity) : UniRx
  • 스칼라 : RxScala
  • 클로저 : RxClojure
  • C ++ : RxCpp
  • 루아 : RxLua
  • 루비 : Rx.rb
  • 파이썬 : RxPY
  • 이동 : RxGo
  • 그루비 : RxGroovy
  • JRuby : RxJRuby
  • Kotlin : RxKotlin
  • 스위프트 : RxSwift
  • PHP : RxPHP
  • 엘릭서 : 리액 시브
  • 다트 : RxDart

1

오늘은 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 전문가가 더 나은 솔루션을 제공 할 수있을 것입니다.


1
중위 연산자를 정의 할 수도 있습니다. infix :) x |> f = f x
Jamie
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.