6
let inline myfunction x y = ...

let inline mycurried = myfunction x // error, only functions may be marked inline

inline関数を明示的にカリー化することは不可能のようです。mycurriedということで、ちゃんと呼ばれてinlinedもちゃんと取れないんmyfunctionですね?inlined

これは、カリー化された関数の欠点の 1 つと見なすことができますか?

4

3 に答える 3

5

あなたの質問は、ポイントフリー関数をインライン化できるかどうかだと思います。

あなたが見つけた制限は、カリー化された関数によるものではありません。あなたの例では、カリー化された関数が右側にあり、左側にポイントフリー関数があることに注意してください。

F# では、定数ではなく、関数のインライン化のみが許可されます。

型推論が(ポイントフリー)関数であることを発見するのに十分スマートであることを考えると、これはバグと見なされる可能性があると思うかもしれませんが、副作用に関するTomasのメモを読んでください。

どうやら、コンパイラが左側に識別子のみを見つけると、次のエラーで失敗します。

let inline myfunction x y = x + y

let inline mycurried  = myfunction 1

--> Only functions may be marked 'inline'

ブライアンが言ったように、回避策は両側に明示的なパラメーターを追加することです:

let inline mycurried x  = (myfunction 1) x

しかし、あなたの関数はもはやポイントフリーではありません。それは次と同じです:

let inline mycurried x  = myfunction 1 x

もう 1 つの方法は、明示的なジェネリック パラメーターを追加することです。

let inline mycurried<'a>  = myfunction 1

汎用パラメーターが左側に明示的に存在する場合、コンパイルされます。

エラーメッセージを削除して、次のような警告に変えてほしい:

Since only functions can be 'inline' this value will be compiled as a function.

アップデート

Tomas さん、回答 (および反対票) に感謝します。

私の個人的な意見では、これは警告であるべきです。そのため、コードのセマンティックが最終的に変更されることは承知していますが、その後どうするかを決めるのはあなた次第です。

インラインは「単なる最適化」であると言いますが、それは完全に真実ではありません。

. すべての関数をインライン化するだけでは、最適なコードは保証されません。

. 静的制約を使用したい場合は、インラインを使用する必要があります。

F# ライブラリが既に行っているように、(一種の) ジェネリック定数を定義できるようにしたいと考えています (つまり、GenericZero と GenericOne)。コードが純粋であることはわかっているので、毎回実行されるかどうかは気にしません。

于 2012-09-21T09:58:26.683 に答える
4

両側に明示的なパラメータを追加する必要があると思います(私は試していませんが):

let inline myfunction x y = ... 

let inline mycurried y = myfunction 42 y  // or whatever value (42)
于 2012-09-20T22:43:41.843 に答える
2

コンパイラはinline、関数を定義する on let バインディングのみを許可します。これは基本的に、 F#の値の制限で起こっていることと同じです(また、こちら参照してください)。ブライアンが言うように、関数にパラメーターを追加することで、これを簡単に回避できます。

なぜこの制限が存在するのですか? そこにない場合、追加inlineするとプログラムの意味が変わり、それは悪いことです!

たとえば、次のような関数があるとします (変更可能な状態を作成し、カウンター関数を返します)。

let createCounter n = 
  let state = ref n
  (fun () -> incr state; !state)

さて、次のコード:

let counter = createCounter 0

...複数回使用できる単一のグローバル関数を作成し(call counter())、1から始まる一意の整数を提供します。次のようにマークできる場合inline

let inline counter = createCounter 0

... を使用するたびcounter()に、コンパイラはそれを に置き換える必要がcreateCounter 0 ()あるため、カウンターを呼び出すたびに 1 を取得します!

于 2012-09-21T10:34:14.240 に答える