アドバンスドF


これは私が無視した私の個人的なブログに使用された記事の適応です.元来は2019年のF .
閉じるこの動画はお気に入りから削除されています.私はf .私もC - CHERUNIが好きです、そして、私が生態系の両方を支配しているときでさえ、2つを互いと一緒に遊ぶために得ることは最も簡単なものでありません.さらに悪いのは、誰かが書いたコードを使う必要があるときです.ああ私の神、どこでプログラムを学ぶのですか?見て、我々はすべてそこに行ってきた.いくつかのAPIだけでは、特に恐ろしい時に消費するときはひどい感じている.
それではどのように対処するのですか?多くの人々にとって、彼らはF .

より良い方法があります.そして、それはそんなに多くの仕事を必要としません.
私は、主に図書館作者がこの情報を使用して、可能なときより良いF - Count -サポートを提供して、コミュニティがより少しのF - Sung支持を提供するのを援助するために使用することを望みます.

ライブラリ例


この記事のために、私はあらゆるF - Chunperプログラマーの最悪の悪夢を書きました:私が生産することができた最も非常に命令的で、手続き的で汚いライブラリ.そして、あなたのマネージャーが馬鹿か何かであるので、あなたは何かを使用する際に選択をしません.ライブラリは単純です:1つの特殊なスタック型Double . あなたはそれをチェックアウトすることができますGitHub .
通常、人々はアセンブリをマークするならばCLSCompliant それから、すべては素晴らしいです、そして、あらゆる言語はAPIを消費することができます.これは半分本当です.すべてがAPIを消費することができます.私はすべてが汚れを食べることができることをかなり確信していますが、それはあなたまたは私がしたいことを意味しません.例のライブラリをマークしたCLSCompliant , しかし、それは悪いです.私はそれを書くことの中で死にました.
APIを見てみましょう.
void Add();
void Add(out Double result);
void Subtract();
void Subtract(out Double result);
void Multiply();
void Multiply(out Double result);
void Divide();
void Divide(out Double result);
//... As well as everything Stack<Double> would already have
算術のスタックAPIを使用して、これがどれだけ悪いかを見てみましょう3 * 5 - 8 .
let stack = DoubleStack()
stack.Push(3.0)
stack.Push(5.0)
stack.Multiply()
stack.Push(8.0)
stack.Subtract()
だから、それは素晴らしいことではない.それは動作し、それは言語間で同一です.しかし、私たちがfというもので働いていたいAPIの種類でない人.しかし、他の方法については、アウトパラメータを持つもの?
let stack = DoubleStack()
let mutable result = ref 0.0
stack.Push(3.0)
stack.Push(5.0)
stack.Multiply(result)
あなたは、私がなぜ私が中で死んだと言うかについて見ます.きっとここに希望はない.確かに、これはあなたがそれを吸い上げて、それとしてそれを使うか、F - Ken - HeyフレンドリーなAPIであなた自身を書くことがとても遠くにありました.

この記事の途中で、私はあなたが特定される非常に機能感APIにこれを変える方法を示します.

機能性プッシュ/ポップ/ピーク


良い出発点は、私たち自身のスタックパイプラインを実装することによって、Push ()、pop ()、およびpeek ()を機能させることです.
let ( |=> )(stack:DoubleStack)(value) = stack.Push(value)
let stack = DoubleStack() |=> 5.0
と同様に我々は作業パイプラインがあります!正しい?いいえ、我々は、単一の操作を動作しているが、これは同じ状況で、塗料の異なるコートで私たちを残します.パイプラインを連鎖してください、そして、あなたは問題を見るでしょう.関数呼び出しでスタックを返す必要があります.
let ( |=> )(stack:DoubleStack)(value) =
    stack.Push(value)
    stack
let stack = DoubleStack() |=> 5.0 |=> 3.0
stack.Multiply()
Assert.Equal(15.0, stack.Peek())
それは既に良い量を探している.しかし、まだ行く方法.他の2つの方法を気にしましょう.
let inline pop (stack:DoubleStack) = stack.Pop()
let inline peek (stack:DoubleStack) = stack.Peek()
これは非常に簡単な翻訳です.彼らがインラインに並んでいるように簡単です.これらの種類のメソッドはバインドするのが最も簡単で、あなたがすでによく知らなければならない何かです.これらすべてを組み合わせて、我々は今、機能を見始めている何かを残しているが、まだ明らかにまだありません.
let stack = DoubleStack() |=> 5.0 |=> 3.0
stack.Multiply()
Assert.Equal(15.0, peek stack)

機能オブジェクト


これは深いものです.なぜなら、それは問題の大きな問題ではありませんが、解決するのは容易ではないからです.あなたはまだ物事に対処することができます.そう、DoubleStack() 宣言時にパイプラインの先頭に少し迷惑です.世界の終わりではないが、我々はより良い行うことができます.
type Pipeline =
    static member Pipe(left:DoubleStack, right:float) =
        left.Push(right)
        left
    static member Pipe(left:float, right:float) =
        let result = DoubleStack()
        result.Push(left)
        result.Push(right)
        result

let inline private pipe< ^t, ^a when (^t or ^a) : (static member Pipe : ^a * float -> DoubleStack)> left right =
    ((^t or ^a) : (static member Pipe : ^a * float -> DoubleStack)(left, right))

let inline ( |=> )(left:^a)(right:float) = pipe<Pipeline, ^a> left right
一体何がこれですか.私は、これが若干の空想的な黒い魔法でないと約束します.一度に一つのことをしましょう.
最初はPipeline 定義した型.これは関数や演算子と同じ視認性を持っていなければなりません.その中で、私たちはPipe() スタティックです.ここで何を定義することができますこれらは呼び出されている実際のメソッドです.最初のものは既に定義したものです.スタックとフロートを取り、フロートをスタックにプッシュし、スタックを返します.番目の1つは、我々が望んだ動作を追加します:スタックを作成し、左側の値をプッシュし、右の値をプッシュし、スタックを返します.
第二は、F - Chrung ' s型システムに慣れていない人々にとって、おそらく最も威圧的なことであるインラインと一般的な策略である.それは悪くはない、私は約束します.一般的な部分を無視するとpipe のパラメータを2つ指定します.left and right . それほど悪くない.一般的な部分は、2つの静的に解決された型を考慮していると言います.^t and ^a . その静的解像度は重要です、そして、そのため、この機能は絶対にインラインされなければなりません.しかし、私はそれをプライベート、常に作るために撮影したので、表示する必要はありません.残りの総称は^t or ^a , 静的メンバーPipe 署名で^a * float -> DoubleStack . 我々がちょうど話していたそれらの方法を見てください.長く^a 最初のパラメータのうちの1つにマッチします.この関数の定義部分の中で一見繰り返すコードは、このように解決されたメソッドを呼び出して、(left, right) . そこは、あまり悪くなかった.私はまだそれはブラックマジックだと思うのも私は認めるでしょう.
番目の部分は、オリジナルのスタックパイプライン演算子にわずかに変更されます.また、これは現在インライン化される必要があります.両方の機能のインライン化は非常に重要です.同様に、左側のパラメータを^a , それが静的に解決するように.それから、我々は我々がしていたものの代わりにブラックマジック機能を呼びます.ここはどこです^t and Pipeline 遊びに出る.我々が働いているライブラリを第3者と仮定すると、インスタンスメンバを追加できませんPipe それに.そして、我々は確かにインスタンスメンバーをDouble ! この追加のパラメーターは、これらのメソッドも定義されている型に対してです.現在、それは我々自身のタイプの中に同様に見えるのを知っています.
これはどれくらい進歩しましたか.
let stack = 5.0 |=> 3.0
stack.Multiply()
Assert.Equal(15.0, peek stack)
全体の多くは変わっていません、しかし、それは確かによりきれいに見えます.長いパイプラインを試して、それはまだ動作します.
もう一つsimpler way , これを達成する.あなたができるときそれを使用しますが、私の経験から、このアプローチは、多くの状況では可能ではありません.この単純なアプローチは、この例では動作しません.
私は、これが最も便利であるメソッドをマッピングするとき、CurryingとPipeliningが可能であるように便利であるとわかりました.これはしばしばパラメータの並び替えを意味します.他の用途を見つけることができます.あなたがそうすることができるので、私はこれをすることを勧めません.

関数スタック演算


最後の残り物はそれらの厄介な算術法です.確かに、我々は最終的に我々は完全にこの機能的な、パイプライン重い、環境にバインドすることはできません何かに実行してきました.正しい?
実際、この1つは本当に簡単です、我々がすでに設定したもので
let add (stack:DoubleStack) =
    stack.Add()
    stack
など.それです.真剣に、それはない.スタック・パイプライン演算子のために、正確なシンボルFira Code または関連するフォントですが、関数のパイプライン演算子とまったく同じ優先順位と結合度を持っていますので、追加するには何も新しいことはありません.
すべてをまとめると、
let stack = 3.0 |=> 5.0 |> mul |=> 8.0 |> sub
Assert.Equal(7.0, peek stack)
私は、それが可能であるとあなたに言いました.😉
多くのことがありますが、この記事は多くをカバーしており、私は圧倒的な情報を提供したくない.それで、将来より多くを期待してください.