F#では、パイプフォワード演算子|>
の使用は非常に一般的です。ただし、Haskellでは、(.)
という関数構成が使用されているのを見ただけです。私はそれらが related であることを理解していますが、Haskellではパイプフォワードが使用されていないか、それとも何か他のものであるという言語上の理由がありますか?
私は少し推測しています...
Culture:|>
はF#の「カルチャ」の重要な演算子であり、おそらくHaskellの.
と同様だと思います。 F#には関数構成演算子<<
がありますが、F#コミュニティではHaskellコミュニティよりも points-free style が少ない傾向があります。
言語の違い:両方の言語について比較するのに十分な知識はありませんが、letバインディングを一般化するためのルールは、これに影響するほど十分に異なっています。たとえば、私はF#で時々書くことを知っています
let f = exp
コンパイルされず、明示的なイータ変換が必要です:
let f x = (exp) x // or x |> exp
コンパイルします。これはまた、人々をポイントフリー/合成スタイルから遠ざけ、パイプラインスタイルへと導きます。また、F#型の推論ではパイプラインが必要になることがあるため、既知の型が左側に表示されます( here を参照)。
(個人的には、ポイントフリーのスタイルは読めないと思いますが、あなたがそれに慣れるまで、すべての新しい/異なるものは読めないと思われます。)
どちらもどちらの言語でも潜在的に実行可能であり、歴史/文化/事故は、各コミュニティが異なる「アトラクター」に定住した理由を定義するかもしれません。
F#では、左から右への型チェックのため(|>)
が重要です。例えば:
List.map (fun x -> x.Value) xs
xs
の型がわかっていても、ラムダへの引数x
の型は、タイプチェッカーがそれを見た時点ではわからないため、通常は型チェックしません。 x.Value
の解決方法がわからない。
対照的に
xs |> List.map (fun x -> x.Value)
xs
のタイプによりx
のタイプが認識されるため、正常に機能します。
x.Value
などの構造体に含まれる名前解決のため、左から右への型チェックが必要です。 Simon Peyton Jonesは proposal を作成してHaskellに同様の名前解決を追加しましたが、代わりにローカル制約を使用して型が特定の操作をサポートするかどうかを追跡することを提案しています。したがって、最初のサンプルでは、x
がValue
プロパティを必要とするという要件は、xs
が見つかるまで繰り越され、この要件を解決できます。ただし、これは型システムを複雑にします。
今回は主にHaskell側からの推測...
_($)
_は_(|>)
_の反転であり、ポイントフリーコードを書くことができない場合、その使用は非常に一般的です。そのため、_(|>)
_がHaskellで使用されない主な理由は、その場所がすでに_($)
_に取って代わっているためです。
また、少しのF#の経験から言えば、_(|>)
_はOOのSubject.Verb(Object)
構造に似ているため、F#コードで非常に人気があると思います。 F#はスムーズな機能/ OO統合を目指しているため、_Subject |> Verb Object
_は新しい機能プログラマーにとって非常にスムーズな移行です。
個人的には、左から右にも考えるのが好きなので、Haskellでは_(|>)
_を使用していますが、他の多くの人はそうは思わないでしょう。
私たちは物事を混乱させていると思います。ハスケルズ(.
)は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
HaskellでF#の|>
を使用する場合、- Data.Function は&
演算子です(base 4.8.0.0
以降)。
Haskellでも左から右(メッセージの受け渡し)のスタイルを使用する人もいます。たとえば、Hackageの mps libraryを参照してください。例:
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 (.)
に使用されているのを見てきましたが、特に左から右に最もよく理解される長いチェーンの場合は、自分でよく使用します。
_>>>
_は実際にはControl.Arrowからのものであり、単なる関数以上のもので動作します。
スタイルと文化は別として、これは、純粋なコードまたは不純なコードのいずれかのために言語設計を最適化することに要約されます。
|>
演算子は、主に不純なコードで現れる2つの制限を隠すのに役立つため、F#で一般的に使用されます。
サブタイプはノミナルではなく構造的であるため、OCamlには前者の制限が存在しないことに注意してください。したがって、構造推論は、型推論の進行に合わせて統合によって容易に改良されます。
Haskellは、これらの制限を取り除くことができる主に純粋なコードに集中することを選択する、別のトレードオフを取ります。
F#のパイプフォワード演算子(|>
)vs (&) 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 = infix +右結合性
(.
)は関数合成を意味します。 Math (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
($
)演算子も 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/ にアクセスしてください
サポートします:
Haskellを試す最初の日(Rust and 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のエキスパートがあなたにもっと良い解決策を提供できると思います。