4

これは、パーサー モジュールの関数です。1 行のコードを理解するのが難しい

 let rec e1 tokens =
   match tokens with
    Tokenizer.IfTok :: tokens1 -> 
      let (testAST, tokens2) = e1 tokens1
      in
      (match tokens2 with
          Tokenizer.ThenTok :: tokens3 ->
            let (thenAST, tokens4) = e1 tokens3
            in
            (match tokens4 with
                Tokenizer.ElseTok :: tokens5 ->
                  let (elseAST, tokens6) = e1 tokens5 
                  in
                  (If(testAST, thenAST, elseAST), tokens6)
              | _ -> raise (Syntax ("e1: missing else.")))
        | _ -> raise (Syntax ("e1: missing then.")))
  | _ -> e2 tokens

and e2 tokens = ........

この線の仕組みがよくわからない

let (testAST, tokens2) = e1 tokens1 in

タプルであるローカル変数を宣言していることは知っていますが、値 (testAST、tokens2) はどこから来るのでしょうか? tokens や tokens1 とは関係がないようです。また、この行はタプルを宣言するだけですか、それとも関数を呼び出しますか? ありがとう!

4

2 に答える 2

3

はい、この行は 2 つの変数を宣言し、関数を呼び出してe1、変数を関数呼び出しの結果にバインドします。

変数をバインドするこの方法は、パターン マッチングと呼ばれます。これは、関数の戻り値の型に関する情報に基づいe1ています。コンパイラは、タプルを返すことを認識しており、部分に分解される可能性があり、これらの部分は 2 つの新しい変数にバインドされtestASTますtokens2。これは FP の最も強力な機能の 1 つであり、はるかに読みやすく、柔軟で、簡潔なコードを記述できます。

そのエンティティーの構造 ( pattern ) がコンパイラーに知られている場合は、すべて (例えば、Scala のケース・クラス、Haskell のタプルとリスト、Erlang のレコードなど)に対して実行 ( matched ) することもできます。また、パターン マッチングを使用して、条件に関係のない構造の一部を無視することもできます (たとえば、Haskell で 3 タプルの 2 番目の項目を選択する場合は、値を無視するための特別な記号である を実行します)。selectSecond (_, a, _) = a_

于 2012-10-29T23:11:03.557 に答える
0

という名前の関数を呼び出していますe1。実際、これはまさにそれが現れる関数です。つまり、これは への再帰呼び出しe1です。この関数はペア (2 タプル) を返します。

これはかなり標準的な再帰降下解析のように見えます。

于 2012-10-29T23:00:26.380 に答える