9

Shadowing と Nested 関数の仕組みを理解したい。例えば:

let func y =
    let dup y = y + y
    let z = dup y
    let dup y =
        let dup z =
            let y = y * z
            y
        let z = y
        y
    dup z + z;;

val func : int -> int

> func 3;;
val it : int = 12

誰かがここで何が起こっているのか説明できますか?

4

2 に答える 2

17

あなたのコードは次のようになります。ここでは、シャドウイングがどのように発生しているかを視覚化するのに役立つように、名前のインスタンスに番号を付けただけです。

let func y0 = 
  let dup0 y1 = y1 + y1
  let z0 = dup0 y0
  let dup1 y2 = 
    let dup2 z1 = 
      let y3 = y2 * z1 
      y3
    let z2 = y2 
    y2 
  dup1 z0 + z0

もちろん、これはさらに単純化できます。dup2z2は使用されないため、はdup1と同等let dup1 y2 = y2であり、関数全体は と同等です。

let func y0 =
  let dup0 y1 = y1 + y1
  let z0 = dup0 y0
  dup1 z0 + z0

これはに相当します

let func y0 =
  let z0 = y0 + y0
  z0 + z0

代用で。これは

let func y0 = 4 * y0

これは役に立ちますか?

于 2010-03-19T14:57:00.527 に答える
14

@kvbは、コードがどのように評価されるかを示す非常に良い説明を提供すると思います。このコードは、ネストされた関数シャドウイングを非常に紛らわしい方法で組み合わせています :-)。2 つの概念を別々に見てみると便利だと思います。

シャドウイングを使用すると、宣言内の新しい値letまたは構成内の値バインディングによって値を非表示にできますmatch。これは、元の値にアクセスできなくなることを意味します。より簡単な例を次に示します。

let foo num =
  let num = num + 20 // Line 2
  let num = num * 2  // Line 3
  num

ここでは、 という名前の引数を取る関数を宣言しますnum。1 を引数として関数を呼び出すとしましょう。2 行目では、同じ名前で新しい値を宣言します。これは1 + 20に初期化され、つまり21です。3 行目は再び新しい値を宣言し、それを21 * 2に初期化します(値が21である、最後に宣言されたnumシンボルを参照するため)。4 行目で、最後に宣言されたnumシンボルに再びアクセスし、 42を返します。

これは主に、後続のすべての計算で使用する必要がある新しい値を計算する計算がある場合に役立ちます。シャドウイングを使用すると、以前の値を非表示にできるため、誤って元の値を使用する危険はありません。

ネストされた関数は、外側の関数のパラメーターを使用するローカル ユーティリティの計算を行う必要がある場合に非常に役立ちます。例えば:

let times x nums = 
  let timesUtil y = y * x
  for n in nums do
    printfn "%d" (timesUtil n)

ここでは、timesUtil任意の数を値x(times関数の引数) で乗算するユーティリティ ネスト関数を宣言します。xその後、後で (最後の行で) 使用して、値を引数として再度渡すことなく操作を実行できます。したがって、ネストされた関数の主な興味深い点は、外側の関数によって宣言された値にアクセスできることです。

于 2010-03-19T15:23:59.693 に答える