2013-01-19 24 views
7

私はOCamlでのいくつかのF#コードを変換していると私は、例えば、このパイプライン演算子<|の用途の多くを見ると:変換F#のパイプライン演算子(<|, >>、<<)OCamlの

let printPeg expr = 
    printfn "%s" <| pegToString expr 

<| 、彼らはF#でこの演算子を定義して使用することをわざわざなぜ私は思ったんだけど

# let (<|) a b = a b ;; 
val (<|) : ('a -> 'b) -> 'a -> 'b = <fun> 

彼らはこのような括弧に入れて避けることができるので、それだけで?:

:オペレータは、どうやら同じように定義されています10
let printPeg expr = 
    Printf.printf "%s" (pegToString expr) 

私が言うことができる限り、これは上のF#コードのOCamlへの変換でしょうか?

また、OcamlでF#の<<>>演算子を実装するにはどうすればよいですか? F# sourceから直接

+0

私はOCamlのオープンコードが大量であること、F#に翻訳しやすいこと、Visual Studioを使用できること、そしてここでサポートすることにより、OCamlからF#への翻訳に多くの時間を費やしていますあなたはF#からOCamlに行くことで得るのですか? –

+0

@GuyCoder:まず、私はWindowsではありません。私はLinuxで開発しています。私はMonoを使ってLinux上でF#を開発できると思うが、私はOCamlとそのツールチェーンに精通しており、Monoランタイムに依存したくないと思う。私はOCamlにF#がファンクタとファーストクラスのモジュールのようにないという特徴をいくつか持っています。はい、私は、OCamlからF#へ行くことに関する多くの情報があることに気付きましたが、それほど多くはありません。我々はある種の互換性ライブラリ/層が必要です。 – aneccodeal

+0

[FSharp.PowerPack.Compatibility.dll](https://github.com/fsharp/powerpack/tree/master/src/FSharp.PowerPack.Compatibility)について知っていますか?それはすべてをカバーするものではありませんが、助けになります。私は現在、ファンクショナーとMLコードを翻訳しています。ファンクショナーを初めて初めて迎えてくれました。私は本当に[time travel]を愛していました(http://caml.inria.fr/pub/docs/manual-ocaml- 4.00/manual030.html)OCamlのデバッグ機能OCamlにはたくさんの機能があり、F#と同じくらい頻繁にお勧めします。 :) –

答えて

11

let (|>) a b = b a ;;|>オペレータが簡単になるようだ):

let inline (|>) x f = f x 
let inline (||>) (x1,x2) f = f x1 x2 
let inline (|||>) (x1,x2,x3) f = f x1 x2 x3 
let inline (<|) f x = f x 
let inline (<||) f (x1,x2) = f x1 x2 
let inline (<|||) f (x1,x2,x3) = f x1 x2 x3 
let inline (>>) f g x = g(f x) 
let inline (<<) f g x = f(g x) 
14

彼らはF#でこの演算子を定義して使用することをなぜわざわざ、それはちょうど彼らがそうです括弧を入れることを避けることができますか?

プログラミングの機能的な方法は、一連の関数を通じて値をスレッド化することを前提としているからです。比較:

let f1 str server = 
    str 
    |> parseUserName 
    |> getUserByName server 
    |> validateLogin <| DateTime.Now 

let f2 str server = 
    validateLogin(getUserByName(server, (parseUserName str)), DateTime.Now) 

最初のスニペットでは、値が発生したすべてがわかります。第二のものを読んで、何が起こっているのか把握するために、すべての括弧を通らなければなりません。

This articleについては、機能構成が関係しているようです。

だから、通常の生活では、それはたいていは括約です。しかし、パイプライン演算子は、部分関数アプリケーションとポイントフリーのコーディングスタイルと密接に関連しています。たとえば、Programming is "Pointless"を参照してください。それらは、より高いレベルの機能に渡されたとき

パイプライン|>と関数組成>><<オペレータはhereように、さらに別の興味深い効果を得ることができます。

+0

-1 "プログラミングの機能的な方法は関数の連鎖を通じて値をスレッド化すると仮定しているからです"。もしそれが真実なら、OCamlはF#の前にそのような演算子を持っていました。また、余分なカッコが追加されていないため、例が等価ではありません。 'validateLogin DateTime.Now(getUserByNameサーバ(parseUserName str))'。 –

+5

@JonHarropよくお読みください。私は意図的に 'date'を** secondパラメータ**を作って、' <| '演算子の有用性を実証しました。 – bytebuster

9

OCamlバッテリはこれらの演算子をサポートしていますが、優先順位、連想性、およびその他の構文上の癖(Camlp4など)の理由から、異なる記号が使用されます。使用する特定のシンボルが最近決済されたばかりなので、いくつかの変更があります。参照:Batteries API

val (|>) : 'a -> ('a -> 'b) -> 'b 

機能アプリケーション。 x |> fはf xと等価です。

val (**>) : ('a -> 'b) -> 'a -> 'b 

機能アプリケーション。 f **> xはf xと等価です。 メモこの演算子の名前は石ではありません。すぐに変更されることになっています。

val (|-) : ('a -> 'b) -> ('b -> 'c) -> 'a -> 'c 

機能構成。 f | - gはfun x - > g(f x)です。これは< **を2回適用することと同じです。

val (-|) : ('a -> 'b) -> ('c -> 'a) -> 'c -> 'b 

機能構成。 f - | gはfun x - > f(g x)です。数学的には、これは演算子oです。

しかしBatteries trunkが用意されています

val (@@) : ('a -> 'b) -> 'a -> 'b 

機能アプリケーションを。 [f @@ x]は[f x]と等価です。

val (%) : ('a -> 'b) -> ('c -> 'a) -> 'c -> 'b 

関数の構成:数学的[o]演算子。

"パイプ":機能アプリケーション。 [x |> f]は[f x]と等価です。

val (%>) : ('a -> 'b) -> ('b -> 'c) -> 'a -> 'c 

配管機能の組成。 [f%> g]は[fun x - > g(f x)]です。

+0

+1のBattriesに注目してください。 –

+0

これは知っておくと良いですが、 '<|' camlp4の問題を引き起こしますか? – aneccodeal

+0

いいえ、引用符を使用している場合は '<<' and '>>'としか思えません。 – lukstafi

6

私はなぜF#でこの演算子を定義して使用するのかと思っていますが、そういうわけではありませんか?

優秀な質問。あなたが参照している特定の演算子(<|)は、かなり役に立たないIMEです。まれに括弧を避けることができますが、より一般的には、より多くの演算子をドラッグすることで構文が複雑になります。経験の少ないF#プログラマー(現在は多くあります)がコードを理解するのが難しくなります。だから私はそれを使用を停止しました。

|>演算子は、OCamlに問題がない状況でF#が型を正しく推測するのに役立ちますが、はるかに便利です。 oのタイプは前慣用ソリューションはそう|>使用して、このようなコードを書き換えることであるように、そのfooプロパティを読み込むに推測することができないので、F#で失敗し

List.map (fun o -> o#foo) os 

直接対応:たとえば、ここでいくつかのOCamlでありますF#がfoooの種類を推測することができます使用されます。

os |> List.map (fun o -> o.foo) 

、彼らはまた、構文を複雑にするので、私はめったに他の演算子(<<>>)を使用していません。私はまた、多くの演算子を引き出すパーサーコンビネータライブラリを嫌います。

Bytebusterを与えた例は興味深いです:

let f1 str server = 
    str 
    |> parseUserName 
    |> getUserByName server 
    |> validateLogin <| DateTime.Now 

私はこのように記述します。私のコードにはカッコがありません

let f2 str server = 
    let userName = parseUserName str 
    let user = getUserByName server userName 
    validateLogin user DateTime.Now 

。私の一時的なものは名前を持っているので、デバッガに表示され、それらを検査することができます。また、Intellisenseはマウスをマウスの上に置いたときにタイプ・スローバックを与えることができます。これらの特性は、プロフェッショナルでないF#プログラマーが維持する生産コードにとって有益です。

+1

-1:あなたは質問されていない質問に答えています。個人的な嗜好や、パイプライニングやコンポジション演算子が有用であるとは限りません。また、あなたが私の答えを見直したように、 '|>'を一連の 'let'命令に置き換えることではありません。しかし、型推論についてのあなたの意見は重要だと思われますので、あなたの答えをきれいにすることを考えれば、より建設的に見えます。 – bytebuster

+5

+1答えに余分な情報を与え続けてください。私は何かを知る必要があるので質問をすることは何度もあります。私は何が必要なのか分かりませんので、私が必要とするものではありません。もし私がしたら、私は多くの質問をしないだろう。 |>型推論の有用性は私には理解するのに時間がかかり、ジョンはそれをここでは無料で言います。読者は自由にそれを無視することができます。これはバイトバスターに対するものではありません:)しかし、私はまだSOのエトーに問題があると言います。魚を与えたり、人々に魚を教えることは視力ですか? –

関連する問題