8

これらの機能はまったく同じですか?つまり、1 番目と 2 番目の構文は、最後の構文の便利な省略形ですか? または、理論的または実際的な違いはありますか?もしそうなら、それは何ですか?

let f1 a b = a + b

let f2 a = (fun b -> a + b)

let f3 = (fun a -> (fun b -> a + b) )

たとえば、それらは私には同じように見え、同じf1 5値を返すようです。ここで無効な仮定をしていないことを確認するだけです。言い換えれば、「ええ、私はそれらが同じであると信じています」というものではなく、知識ベースの答えを望んでいます.f2 5f3 5

4

3 に答える 3

8

あなたの仮定は正しいです。この場合、機能はまったく同じです。

これは、生成された IL コード (Craig によるデモ) を調べることで確認できます。また、F# コンパイラによって推論された型を調べることでも確認できます。どちらの場合も、 が表示されますint -> int -> intintF# 言語では、これを受け取って返す関数と見なしますint -> intが、実際には (効率のために) 複数の引数を持つメソッドとしてコンパイルされます。

fun直後に記述let .. =すると、コンパイラはそれを標準関数に変換します。ただし、関数を返す前に計算を行うと、少し異なるコードを書くことができます。

let f1 a b = printfn "hi"; a + b
let f2 a = printfn "hi"; (fun b -> a + b)

この 2 つの関数は非常に異なります。2 番目の関数は、引数を 1 つだけ指定すると "hi" を出力するためです (そして、呼び出すことができる関数を返します)。

> let f = f2 1;;
hi                      // The body is called, prints 
val f : (int -> int)    // and returns function

> f 2;;                 // This runs the body of 'fun'
val it : int = 3        // which performs the additiion

を使用して同じコードを書くことができますf1が、最初のコマンドは単に新しい関数を作成し、2 番目のコマンドは "hi" を出力して追加を行います。

この場合、生成される IL コードはf2異なります。関数(タイプ) を返す関数になりますFSharpFunc<int, int>。F# で表示される型も異なりint -> (int -> int)ますint -> int -> int。これら 2 つの型の値はまったく同じ方法で使用できますが、単一の引数を指定すると、最初の型が何らかの影響を与える可能性があることを示唆しています。

于 2012-10-30T13:05:46.327 に答える
5

のILは次のf1とおりです。

.method public static int32  f1(int32 a,
                                int32 b) cil managed
{
  .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationArgumentCountsAttribute::.ctor(int32[]) = ( 01 00 02 00 00 00 01 00 00 00 01 00 00 00 00 00 ) 
  // Code size       5 (0x5)
  .maxstack  4
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldarg.1
  IL_0003:  add
  IL_0004:  ret
} // end of method Program::f1

...そして f2 の場合:

.method public static int32  f2(int32 a,
                                int32 b) cil managed
{
  .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationArgumentCountsAttribute::.ctor(int32[]) = ( 01 00 02 00 00 00 01 00 00 00 01 00 00 00 00 00 ) 
  // Code size       5 (0x5)
  .maxstack  4
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldarg.1
  IL_0003:  add
  IL_0004:  ret
} // end of method Program::f2

ご覧のとおり、本質的には同じなので、同じです。

于 2012-10-30T13:05:37.883 に答える
5

2 つの機能は同じです。それらは構文上の砂糖と見なすことができます

let f = fun a -> fun b -> a + b

実用上の差はわずかです。f1は、関数が値を返す一方でクロージャーを返すことを強調しておりf2、クロージャーは値を生成します。の使用は、パーサー コンビネーターf2などのコンビネーターを作成する際に、もう少し魅力的です。

ちなみに、F# の関数には同等性がないためf1 5、 とf2 5は異なる値ですが、同じ入力に対して同じ出力を生成します。

于 2012-10-30T13:09:52.747 に答える