2016-07-01 8 views
4

F#で行ったすべての進歩について、コンストラクタとデコンストラクタの構文のさまざまな部分でまだ失われています。F#(関数)に(カスタム)型を代入する

私は再帰的シミュレーションを実行しています。パラメータの1つは停止条件の関数です。私は様々な停止条件を選択できます。私はそれらにすべて同じ署名があるようにする。だから私はそれがカスタムタイプにこれらの機能をロックダウンするために、素敵な、教育だろう決める - 署名を一致させるために起こるだけでなく、任意の関数を送ることができるように:

type StoppingCondition = | StoppingCondition of (ReturnType -> ReturnType -> int -> float -> bool) 

私はだと思いますチュートリアルから、型名と同じコンストラクタ名(混乱している...)を持つ、この権利を行うことは、単一のケースの差別化されたユニオンに対してです。しかし、今、私は、実際の関数にこのタイプを適用する方法を見つけ出すことはできません。

let Condition1 lastRet nextRet i fl = 
    true 

私は条件1がタイプStoppingConditionでも作る方法を教えてください。私はそれが簡単だと思う。しかし、私はストップコンディションを、最初と2番目と最後の言葉として、括弧とコロンの有無にかかわらず置いてみました。そしてすべてが誤りです。

ここに忍耐してくれてありがとう。

EDIT:このパターンを模倣しようとすると

私はすべての良い(この瞬間のように)4つの回答から傾くものを合成しようとするでしょう

s : string = "abc" 

私が書こうとした: Stopping Condition

type StoppingCondition = | StoppingCondition of (ReturnType -> ReturnType -> int -> float -> bool) 

let condition1 lastRet nextRet i fl : StoppingCondition = // BAD 
    //wrong for a type alias, totally wrong for a union constructor 
    true 
    //or 
let condition1 : StoppingCondition lastRet nextRet i fl = // BAD again 
    true 

または他の挿入(コンストラクタがその行に入るようにプレフィックスを付けようとしています)。

今、私は私がしなければならないでしょうに私がなっていたものを手に入れることを参照してください。

type StoppingCondition = | StoppingCondition of (ReturnType -> ReturnType -> int -> float -> bool) 
let conditionFunc1 lastRet nextRet i fl = //... 
    true 
let stoppingCondition1 = StoppingCondition conditionFunc1 
    //or 
let stoppingCondition2 = StoppingCondition <| (func lastRet nextRet i fl -> false) 
    //and there's another variation or 2 below 

そして、何このアプローチには大きな負のは、労働組合の種類が異なっている方法ですと、私は感謝していませんでした型エイリアス。タイプエイリアスof stringは、宣言されたときに文字列関数を許可します - 実際には文字列であり、 "文字列のもの"を1つのケース識別したユニオンof string - これは文字列ではありません。 (または、それらの関数のバージョンを文字列関数のラッパーかもしれない)あなたの型に書き出します。)同様に、my関数の型エイリアスはそれらのパラメーターを受け取ります。私の関数のDUは単なるラッパーであり、 。

let x = stoppingCondition1 ret1 ret2 2 3.0 // BAD 
    //"stoppingCondition1 is not a function and cannot be applied" 

を、十分な値は、ラッパーを回避するためにここに私の場合はそこではないですが、タイプの別名が動作します:引数がこれは判別組合では動作しません。

type StoppingAlias = ReturnType -> ReturnType -> int -> float -> bool 
let stoppingCondition:StoppingAlias = fun prevRet nextRet i x -> true 
let b = stoppingCondition ret1 ret2 10 1.0 // b = true 

私はちょうど言ったことがまったくないかもしれないが、私はもっと近いと思う。

編集2:

サイドノート。私の質問は、関数の型を定義することです。そして、それは型エイリアスと共用体型を使って比較されます。私はこれらをしようで働いていたとして、私はまたタイプの別名を使用することについて、このことを学んだ:

type Adder = decimal -> decimal -> decimal 
let f1 : Adder = (fun x y -> x + y) 
    //or 
let f2 : decimal -> decimal -> decimal = fun x y -> x + y 

が、これらは間違っている::

これは(:https://fsharpforfunandprofit.com/posts/defining-functions/から)作品

let (f2 : Adder) x y = x + y // bad 
let (f3 x y) : (decimal -> decimal -> decimal) = x + y // bad 
let (f3 : (decimal -> decimal -> decimal)) x y = x + y // bad 

F# Type declaration possible ala Haskell?

(また、「タイプを割り当てる」というのは正しいことではありません)

答えて

3

述べてきたように、あなたは例えば、適切な関数からStoppingConditionのインスタンスを作成する必要があります。

let Condition1 = StoppingCondition (fun _ _ _ _ -> true)` 

奇妙なインデントや余分な括弧なしでこれを行う一つの良い方法は、後方パイプです:

let Condition1 = StoppingCondition <| fun lastRet nextRet i fl -> 
    // Add function code here 

署名は、4つのカレー化されたパラメータの代わりにレコードの種類を正当化するのに十分な長さである可能性があります。それはスタイルの問題とそれがどのように使われるかという問題です。

let testStopCondition (StopCondition c) input = c input 
+0

ありがとうございました。私はここで得た4つの有益な答えにはまだ取り組んでいます。私は組合のコンストラクタの理解を真っ直ぐにする必要があり、それはキャスト関数ではないと思う。再度、感謝します。 – RomnieEE

+0

あなたの例では、関数を呼び出すためのパターンで関数をラップしなければならないと、DUを(間違って)使用しようとするときに欠けていたものになります。 (そして、あなたの答えがこの時点で唯一のものではないことを知っています。) – RomnieEE

+0

@RomnieEE喜んで私は助けることができました。 DUの「誤った」使用はまったくありません。そのような単一のケースのタイプは、型の安全性を追加するための完全に正常で意図された方法です。タイプとその唯一のケースに同じ名前を付けることも普通です。型とケースのコンストラクタは全く同じ概念ではないことに注意してください。 (そして、パターンとしてのセマンティクスは、再び異なります。) – Vandroiy

4

「タイプにする」ことはできませんStoppingConditionあなたはタイプStoppingConditionの値を宣言し、DUケースコンストラクタのパラメータとしてCondition1を渡す:

let stop = StoppingCondition Condition1 

ことを意味し、しかし、あなたは、単一DUケースに含まれる機能にアクセスするたびに、あなたがしなければならないこと何らかの形でパターンマッチします。それは迷惑になることがあります。

のいずれかの機能を停止条件として有効にする機能はありません。しかし、それは「不適切」機能を渡して「偶然」を回避するのに十分な特異的であるように思われる - それで、あなたはシンプルな何かができる - あなたの特定の関数型の型の別名としてStoppingConditionを定義します。今すぐ

type StoppingCondition = ReturnType -> ReturnType -> int -> float -> bool 

タイプを指定する必要がある場合はどこでもStoppingConditionを使用できます。実際に渡した/返す値は、ReturnType -> ReturnType -> int -> float -> boolという署名を満たす関数になります。

+0

ありがとう:パターンとそれをアンラップ、StopCondition内の関数を呼び出すには

type MyInput = { LastReturn : ReturnType NextReturn : ReturnType MyInt : int MyFloat : float } type StopCondition = StopCondition of (MyInput -> bool) let impossibleCondition = StopCondition (fun _ -> false) let moreComplicatedCondition = StopCondition <| fun inp -> inp.MyInt < int (round inp.MyFloat) 

:結果は次のようになります。私はまずタイプエイリアスを作った。そしてそれは働いた。私は運動として単一のケースユニオンを試みました。 (そして、私のチュートリアルのチュートリアルのオンラインでは、単一のケースのユニオンのための関数ではないシンプルなタイプを使用しています...)私は、ユニオンの使用法の説明をする必要があります。しかし、私はコードのエイリアスに終わるだろうと思う。私はそれがそのようにうまくいくはずだとあなたに同意する。再度、感謝します。 – RomnieEE

+0

ありがとう:私は機能を使用するためにパターンマッチする必要があることに言及することは、私が実際にDUを使用する方法を知りませんでしたどこを参照するのに役立ちます。実際、DUコンストラクタをキャスト関数としてイメージ化していました。そして、私は文字列の 'EmailAddress'のDUのための単一のケースを言うより単純なケースでさえ - それに"文字列のもの "を行うためにその型のインスタンスを解体しなければならないということを忘れ、ありがとう。 – RomnieEE

3

関数の戻り値の型は、次のように行われている指定:もちろん

let Condition1 lastRet nextRet i fl :StoppingCondition= 
    true 

、これは真コンパイルされません正しい型ではありません。

私はタイプが、それは、関数の引数が含まれているように見えるようしたい、実際の定義は、しかし

let Condition1 :StoppingCondition= 
    true 

に近いと思います。この上で拡大

、あなたは次のような関数を定義することができます

let Condition1=fun a b c d -> StoppingCondition(fun a b c d -> whatever) 

が、この全体のことはかなり醜いです。

現実的に、私はとても

+0

ありがとうございます。私は近づいていると思う。私はあなたが疑うものに同意すると思います。戻り値ではなく 'Condition1'を' StoppingCondition'型にします。したがって、2番目のブロックはそのパスにあります。しかし、そのブロックでは、 'Condition1'はもはや引数を持ちません。だから、私は何もすることはありません。 (実際の関数はもちろん 'true'を返すだけではありません - 私はコードを省略しました。)どうやって引数も取得できますか?彼らは私の名前を使用する必要があります。これが本当に混乱したり混乱したように聞こえる場合は、私が混乱し混乱させているからです。ありがとう。 – RomnieEE

+0

@RomnieEE - あなたのアプローチはちょっと変わったと思いますが、私は解決策を出しました。 –

+0

よろしくお願いいたします。それは私の低い理解のために変だ。ありがとう。 – RomnieEE

1

に一致するようにタイプを強制する、アレイ内のすべての機能を入れた方が良いと思い、あなたがStoppingCondition秒とすることがあります物事が作成しているように私には思えますいくつかの所定のタイプの停止条件。ここで

は、いくつかの可能な停止条件のいくつかの例は以下のとおりです。

let stopWhenNextGreaterThanLast = StoppingCondition (fun last next _ _ -> next > last) 

let stopWhenLastGreaterThanLast = StoppingCondition (fun last next _ _ -> last> next) 

(私は私の停止条件の定義に使用していないパラメータを強調してきた)

うまくいけば、あなたは両方のことがわかりますタイプStoppingConditionのこれらの値。

次にあなたが停止条件は、いくつかのパラメータが与えられた満たされていたかどうかを判断する機能が必要になる場合があります:

let shouldStop stoppingCond last next i value = 
    match stoppingCond with 
    |StoppingCondition f -> f last next i value 

この機能は、停止条件を取り、あなたの再帰のさまざまな状態とに応じてtrueまたはfalseを返します。それが今停止するかどうか。

これは実際にこのアプローチを活用するために必要なものです。


あなたは、複数の潜在的な停止条件をカバーするために、このような何かをすることによって、このアプローチを拡張することができます:今、私たちは一つの条件を持っている場合

type StoppingCondition = 
    | StoppingCondition of (ReturnType -> ReturnType -> int -> float -> bool) 
    | Or of StoppingCondition * StoppingCondition 

そしてshouldStop機能に

let rec shouldStop stoppingCond last next i value = 
    match stoppingCond with 
    |StoppingCondition f -> f last next i value 
    |Or (stp1, stp2) -> (shouldStop stp1 last next i value) || (shouldStop stp2 last next i value) 

を変更しますそれが満たされた時点で停止するか、複数の条件が満たされた場合は、いずれかが満たされているかどうかを確認することができます。

その後、あなたは基本条件から新しい停止条件を一緒にOrできます

let stopWhenIIsEven = StoppingCondition (fun _ _ i _ -> i % 2 = 0) 

let stopWhenValueIsZero = StoppingCondition (fun _ _ _ value -> value = 0.0) 

let stopWhenIEvenOrValueZero = Or (stopWhenIIsEven, stopWhenValueIsZero) 
+0

例と説明をありがとう。私がやっていることの一つは、(単一のケースの)共用体のコンストラクタをキャスト関数と多かれ少なかれ混乱させることだと思います。私はちょうど1つにチェックを入れなければならない前に、4つの良い答えをすべて勉強するのにもう少し時間を取るつもりです。しかしもう一度ありがとう。 – RomnieEE

+0

ここでもう一度言及しますが、すべての答えに公正になるように、 'StoppingCondition'のポイントを展開して、私がDUを使用することを理解していると思う場所に移動する必要があります。この例をありがとう。 – RomnieEE

関連する問題