回答:
私は少し投機的です...
カルチャー:|>
F#の「カルチャー」で重要な演算子だと思います.
。おそらくHaskell でも同様です。F#には関数構成演算子<<
がありますが、F#コミュニティはHaskellコミュニティよりもポイントフリースタイルを使用する傾向があると思います。
言語の違い:両方の言語について比較するのに十分な知識はありませんが、おそらくletバインディングを一般化するための規則は、これに影響を与えるほど十分に異なっています。例えば、私はF#で時々書くことを知っています
let f = exp
コンパイルされず、明示的なeta変換が必要です:
let f x = (exp) x // or x |> exp
コンパイルするために。これはまた、人々をポイントフリー/作曲スタイルから遠ざけ、パイプラインスタイルに向けます。また、F#の型推論ではパイプライン化が必要になる場合があるため、既知の型が左側に表示されます(ここを参照)。
(個人的には、ポイントフリースタイルは判読できませんが、慣れるまでは、すべての新しいものや異なるものは判読できないように思われます。)
私はどちらもどちらの言語でも潜在的に実行可能であると思います、そして歴史/文化/事故は、各コミュニティが異なる「アトラクタ」に定住した理由を定義するかもしれません。
.
and $
を使用しているため、人々は引き続きそれらを使用しています。
(|>)
左から右への型チェックのため、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は、Haskellに同様の種類の名前解決を追加することを提案していますが、代わりにローカル制約を使用して、型が特定の操作をサポートするかどうかを追跡することをお勧めします。したがって、最初のサンプルでx
は、Value
プロパティを必要とする要件が見つかるまで繰り越されxs
、この要件を解決できます。ただし、これは型システムを複雑にします。
より多くの推測、今回は主にHaskell側から...
($)
はの反転であり(|>)
、ポイントフリーのコードを記述できない場合は、その使用が非常に一般的です。したがって、(|>)
Haskellで使用されていない主な理由は、その場所がすでにに採用されているため($)
です。
また、少しのF#の経験から言えば、OO (|>)
のSubject.Verb(Object)
構造に似ているため、F#コードでは非常に人気があると思います。F#はスムーズな関数型/ OO統合を目指しているため、Subject |> Verb Object
新しい関数型プログラマにとっては非常にスムーズな移行です。
個人的には、左から右に考えるのも好きなので(|>)
、Haskellで使用しますが、他の人はそうは思わないでしょう。
Data.Sequence.|>
、$>
競合を避けるために妥当なようです。正直なところ、見栄えの良い演算子はそれほど多くないので|>
、両方に使用し、ケースバイケースで競合を管理します。(また、私は別名Data.Sequence.|>
として単に誘惑されますsnoc
)
($)
および(|>)
アプリケーションではありません構成されています。2つは(質問のメモのように)関連していますfc
が、同じではありません((Control.Arrow.>>>)
関数用です)。
|>
UNIXを思い出させ|
ます。
|>
F#のもう1つの利点は、Visual StudioのIntelliSenseに優れたプロパティがあることです。と入力|>
すると、左側の値に適用できる関数のリストが表示され.
ます。これは、オブジェクトの後に入力した場合と同じです。
混乱していると思います。Haskellの(.
)はF#の()と同等>>
です。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
$
: -演算子逆に、あなたも簡単としてそれを定義したことができますa |> b = flip ($)
あなたが行うことができます例えばパイプラインのF#に同等になる[1..10] |> map f
.
)は()と同じだと思いますが、<<
(>>
)は逆の構成です。それは( >> ) : ('T1 -> 'T2) -> ('T2 -> 'T3) -> 'T1 -> 'T3
vs( << ) : ('T2 -> 'T3) -> ('T1 -> 'T2) -> 'T1 -> 'T3
.
同等ではないと思います>>
。F#にあるかどうかはわかりませんが<<
、Elmの場合と同じです。
|>
HaskellでF#を使用する場合は、Data.Functionが&
演算子です(以降base 4.8.0.0
)。
&
する理由は何|>
ですか?の|>
方がはるかに直感的で、Unixパイプ演算子を思い出します。
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 (.)
、特に左から右に最もよく理解される長いチェーンに自分で使用することがよくあります。
>>>
実際にはControl.Arrowからのものであり、単なる関数以外にも機能します。
>>>
で定義されていControl.Category
ます。
F#のパイプ転送演算子(|>
)は、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 |>
?データ関数(&)のドキュメントを参照してください
infixl = infix +左結合性
infixr = infix +右結合性
(.
)は関数構成を意味します。これは、数学では(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($)で定義されます。
(.
)はcreate 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および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のエキスパートがより良い解決策を提供できると私は確信しています。
x |> f = f x
&
はHaskellのもの|>
です。このスレッドの奥深くに埋もれ、数日かけて発見しました。あなたはコードをフォローするために左から右へ自然に読むので、私はそれをたくさん使います。