2017-04-21 48 views
0
let separate = fun formula -> 
    let rec aux = fun counter begin size -> 
    match formula.[begin + size] with 
    | '(' -> aux (counter + 1) begin (size + 1) 
    | ')' -> if (counter - 1) = 0 then ((String.sub formula (begin + 1) size), (String.sub formula (size + begin + 3) ((String.length formula) - (size + begin + 2)))) else aux (counter - 1) begin (size +1) 
    | _ -> aux counter begin (size + 1) 
    in aux 0 (String.index formula '(') 0 
;; 

let main s= 
    print_string (fst (separate s)) 
;; 

main "&(A)(B)" 

大家好。我的問題是,當我執行這個ocaml代碼包含將字符串分成兩部分時,我有這個異常:invalid_argument「String.sub/Bytes.sub」。 我想知道,你們能幫我嗎?異常:Invalid_argument「String.sub/Bytes.sub」ocaml

+1

由於'begin'是OCaml中的關鍵字,因此您在此給出的代碼在語法上不是有效的。你應該給出一個簡短的,自包含的,有效的例子來說明你的問題。作爲一般觀察,'String.sub'需要第一個int參數爲> = 0且<=字符串的長度,它要求第二個int> = 0,並且它要求和爲<=字符串的長度。 –

回答

0

由於您使用的是關鍵字begin,因此您的代碼無法編譯。

一旦修改:

let separate = fun formula -> 
    let rec aux = fun counter b size -> 
    match formula.[b + size] with 
    | '(' -> aux (counter + 1) b (size + 1) 
    | ')' -> if (counter - 1) = 0 then ((String.sub formula (b + 1) size), (String.sub formula (size + b + 3) ((String.length formula) - (size + b + 2)))) else aux (counter - 1) b (size +1) 
    | _ -> aux counter b (size + 1) 
    in aux 0 (String.index formula '(') 0 
;; 

現在,爲了獲得異常更多的知名度,補充一點:

let() = Printexc.record_backtrace true;; 

編譯(使用ocamlbuild)並運行它,你會得到某物,如:

Fatal error: exception Invalid_argument("String.sub/Bytes.sub") 
Raised at file "pervasives.ml", line 33, characters 20-45 
Called from file "string.ml" (inlined), line 47, characters 2-23 
Called from file "sep.ml", line 5, characters 75-153 
Called from file "sep.ml" (inlined), line 11, characters 22-34 
Called from file "sep.ml", line 15, characters 0-14 
2

其他答案和頂部的第一條評論都指出了一個誤用的關鍵字begin。這是一個小問題,但沒有解決安東尼奧問的問題。對於初學者,我不熟悉你使用你的函數的上下文,我只是想告訴你你的程序在基於跟蹤的方法出錯的地方。

首先,我對您的代碼進行一些修改,以使其更具可讀性,而且也更容易找出棧幀裏的東西出了問題:

let separate = fun formula -> 
    let rec aux = fun counter start_position size -> 
    match formula.[start_position + size] with 
    | '(' -> aux (counter + 1) start_position (size + 1) 
    | ')' -> if (counter - 1) = 0 then (
     (Printf.printf "%d %d %d\n" counter start_position size); 
    (
     ((Printf.printf "pass1\n"); (String.sub formula (start_position + 1) size)) 
     , 
     (String.sub formula (size + start_position + 3) ((String.length formula) - (size + start_position + 2))) 
    ) 
     ) 
      else aux (counter - 1) start_position (size +1) 
    | _ -> aux counter start_position (size + 1) 
    in aux 0 (String.index formula '(') 0 
;; 

separate "&(A)(B)";; 

(* 
1 1 2 
Exception: Invalid_argument "String.sub/Bytes.sub". 
Raised at file "pervasives.ml", line 33, characters 25-45 
Called from file "string.ml", line 47, characters 2-23 
Called from file "//toplevel//", line 10, characters 4-108 
Called from file "toplevel/toploop.ml", line 180, characters 17-56 
*) 

運行它,你會發現那麼觸發無效參數異常的呼叫在aux 1 1 2的呼叫中。

然後你就可以使用這些代碼來測試爲什麼出錯:

let (counter, start_position, size) = (1,1,2) in 
let formula = "&(A)(B)" in 
(
(size + start_position + 3) 
, 
(String.length formula) - (size + start_position + 2) 
)  ;; 

(* 
- : int * int = (6, 2) 
*) 

這就是你怎麼知道爲什麼String.sub不接受你的論點:

String.sub "&(A)(B)" 6 2;; 
(* Exception: Invalid_argument "String.sub/Bytes.sub". 
Called from file "toplevel/toploop.ml", line 180, characters 17-56 *) 

這是遠因爲我可以幫助你。在OCaml中調試需要時間,但它是可行的。回到良好的印刷技巧。 我希望這是足夠的信息,讓你明白爲什麼你的邏輯在這裏有問題。我希望你能根據你的問題背景找出解決問題的方法。