2010-05-17 40 views
8

我是OCaml新手,我正在嘗試編寫一個簡單的OCaml類語法,而我無法弄清楚這一點。我的語法允許這樣的事情:關於ocamlyacc,函數應用語法和優先級

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

但是,如果我想使用這樣定義的功能,我可以這樣寫:(sub 7) 3但我不能寫sub 7 3,這真讓我心煩。出於某種原因,它被解釋爲好像我寫了sub (7 3)(這將把7作爲函數與參數3)。相關章節有:

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

/* ... */ 

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

謝謝!

回答

5

OCaml的編譯器功能的應用程序如下:(從ocaml/parsing/parser.mly

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

其中simple_expr是可評估的功能,而無需括號可能EXPR值的子集。這排除了與函數調用內聯使用的所有非自支撐構造。它也澄清了子表達式的關聯性,因爲第二個子表達式明確地是一個列表。

至於爲什麼你嘗試使用%left APPLY以獲得正確的關聯性不工作,從註釋OCaml中的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。嘗試通過定義更多規則來創建您想要的關聯性,並查看導致的結果。

+0

謝謝。現在工作:) – Amadan 2010-05-24 00:11:22

+1

您使用的解決方案是什麼? – Thelema 2010-05-24 04:30:23

9

如果你來到了這個問題,並以爲你終於到達那一刻,當你發現你正在尋找什麼,然後很失望,這裏是一個更加明確的答案:

您不能使用%PREC因爲Thelema提到。所以你必須在建立遞歸規則集時定義關聯性。

這裏是一個簡化的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。

在本例中,應用(功能應用)的情況在exp7中。這是因爲在此示例中,Apply被定義爲具有任何模式的最高關聯性。它不具有優先於exp8中的情況的原因是由於將評估應用於對錶達式情況的更多調用,而不是值調用。如果exp8不存在,我們將擁有無限的外觀。

在假設的simple.ml中,Function Application被定義爲以下屬性的表達式:應用expr * expr。由於Apply是左遞歸,我們正在評估正確的表達式(exp8)並在左邊遞歸(exp7)。

0

你也可以使用這樣的事情,以避免破壞表達式分解成這麼多的層次:

%nonassoc LET FUN IF 

%left OR 

%left AND 

%left EQ NE LT LE 

%left PLUS MINUS 

%left MUL DIV