8

私は OCaml の初心者で、単純な OCaml のような文法を書こうとしていますが、これがわかりません。私の文法では、次のようなことができます。

let sub = fun x -> fun y -> x - y;;

ただし、そのように定義された関数を使用したい場合は、: と書くことはできます(sub 7) 3が、 と書くことはできませsub 7 3ん。何らかの理由で、私が書いたかのように解釈されます(これは引数を持つ関数としてsub (7 3)扱われます)。関連するセクションは次のとおりです。73

/* other operators, then at the very end: */
%left APPLY

/* ... */

expr:
    /* ... */
    | expr expr %prec APPLY      { Apply($1, $2) }

ありがとう!

4

3 に答える 3

11

この質問に来て、探していたものを正確に見つけた瞬間に到達したと思ってがっかりした場合は、より明確な答えがあります。

Thelema が言及した理由で %prec を使用することはできません。したがって、再帰的な一連のルールを確立する際に結合性を定義する必要があります。

ここに簡略化された parser.mly があります

    %token <int> Num
    %token <string> Id
    %token TRUE FALSE
    %token LET REC EQ IN FUN ARROW IF THEN ELSE
    %token PLUS MINUS MUL DIV LT LE NE AND OR
    %token EOF          

    %start exp
    %type <Simple.expr> exp

    %%

/* Associativity increases from exp to exp8
 * Each precedence level trickles down to higher level expressions if the pattern is not matched 
 */

/* Parses the LET, LET REC, FUN, and IF expressions */
exp:
      LET Id EQ exp IN exp      { Let($2,$4,$6) }
    | LET REC Id EQ exp IN exp  { Letrec($3,$5,$7) }
    | FUN Id ARROW exp          { Fun($2,$4) }
    | IF exp THEN exp ELSE exp  { If($2,$4,$6) }
    | exp2                      { $1 }

/* Parses OR expressions */
exp2:
      exp2 OR exp3              { Bin($1,Or,$3) }
    | exp3                      { $1 }

/* Parses AND expressions */
exp3:
      exp3 AND exp4             { Bin($1,And,$3) }
    | exp4                      { $1 }

/* Parses EQ, NE, LT, and LE expressions */
exp4:
      exp4 EQ exp5              { Bin($1,Eq,$3) }
    | exp4 NE exp5              { Bin($1,Ne,$3) }
    | exp4 LT exp5              { Bin($1,Lt,$3) }
    | exp4 LE exp5              { Bin($1,Le,$3) }
    | exp5                      { $1 }

/* Parses PLUS and MINUS expressions */
exp5:
      exp5 PLUS exp6            { Bin($1,Plus,$3) }
    | exp5 MINUS exp6           { Bin($1,Minus,$3) }
    | exp6                      { $1 }

/* Parses MUL and DIV expressions */
exp6:
      exp6 MUL exp7             { Bin($1,Mul,$3)}
    | exp6 DIV exp7             { Bin($1,Div,$3)}
    | exp7                      { $1 }

/* Parses Function Application expressions */
exp7:
      exp7 exp8                 { Apply($1,$2) }
    | exp8                      { $1 }

/* Parses numbers (Num), strings (Id), booleans (True | False), and expressions in parentheses */
exp8:
      Num                       { Const($1) }
    | Id                        { Var($1) }
    | TRUE                      { True }
    | FALSE                     { False }
    | LPAREN exp RPAREN         { $2 }

再帰的な回避策は、この質問に関して懸念しているケースを特定するためのものですが、残りの式の結合性を定義するためにどのように適用できるかは簡単にわかります。

このアプローチの要点は、問題のパターンを開始ケース (exp) で定義されたパターンと一致させようとすることです。パターンが一致しない場合は、すぐに続くケース (exp2) への呼び出しをキャッチオール パターンとして残します。その前のいずれかに一致します。パターンが最終的に一致するまで、このアプローチを続けます。これは、最も優先度の高いパターンが最も下のケース (この例では exp8) に存在することを意味します。

この例では、Apply (Function Application) のケースは exp7 にあります。これは、この例では Apply がどのパターンよりも高い結合性を持つように定義されているためです。exp8 のケースよりも優先されない理由は、適用が値の呼び出しではなく、式のケースへのさらなる呼び出しを評価するためです。もし exp8 が存在しなければ、手は無限に見えるでしょう。

架空の simple.ml では、Function Application は次のプロパティの式として定義されています: expr * expr の適用。また、Apply は左再帰であるため、右の式 (exp8) を評価し、左 (exp7) で再帰しています。

于 2011-02-12T10:06:53.000 に答える
5

ocaml コンパイラは次のように関数の適用を行います: (からocaml/parsing/parser.mly)

expr:
...
  | simple_expr simple_labeled_expr_list
      { mkexp(Pexp_apply($1, List.rev $2)) }

ここsimple_exprで、括弧を必要とせずに関数に評価できる可能性のある expr 値のサブセットです。これにより、関数呼び出しでインラインで使用されるすべての非自己ブラケット構造が除外されます。また、2 番目の部分式は明示的にリストであるため、部分式の結合性も明確になります。

%left APPLYocaml の parser.mly のコメントから、正しい結合性を取得するために使用しようとする試みが機能しない理由については、次のとおりです。

We will only use associativities with operators of the kind  x * x -> x
for example, in the rules of the form    expr: expr BINOP expr
in all other cases, we define two precedences if needed to resolve
conflicts.

これは、演算子なしでは結合性に %prec を使用できないことを意味すると思います。より多くのルールを定義することで必要な関連付けを作成してみて、それがどこにつながるかを確認してください。

于 2010-05-23T22:44:34.050 に答える
0

次のようなものを使用して、式を非常に多くのレベルに分割することを回避することもできます。

%nonassoc LET FUN IF

%left OR

%left AND

%left EQ NE LT LE

%left PLUS MINUS

%left MUL DIV
于 2011-11-01T03:45:17.660 に答える