2015-12-08 59 views
1

我有一個程序循環一個字符串並打印出每個字符的dir在OCaml中總計一個變量

我想將這些dir值合計成一個單獨的離散值,我可以打印。

這裏是我當前的代碼:

let word = "(())";; 

let dir = function 
    | '(' -> 1 
    | ')' -> -1 
    | _ -> 0;; 

let z = 
    (String.iter (fun (c: char) -> 
    let d = dir c in 
     Printf.printf "%d is the direction of %c\n" d c 
) word);; 

目前,這樣就會打印出以下幾點:

1 is the direction of (
1 is the direction of (
-1 is the direction of) 
-1 is the direction of) 

而不是打印這些了,我想它總結了4個值( 1,-1,-1,-1)並打印出來:

The overall direction is 0 

如何在OCaml中實現此目的?

回答

1

循環OCaml中以及其它功能的編程語言通常使用遞歸函數來表示。這裏是一個可能的實現:

let count_parens str = 
    let n = String.length str in 
    let rec loop s i = 
    if i < n then match str.[i] with 
     | '(' -> loop (s + 1) (i + 1) 
     | ')' -> loop (s - 1) (i + 1) 
     | _ -> loop s (i + 1) 
    else s in 
    loop 0 0 

或者,使用dir功能:

let count_parens str = 
    let n = String.length str in 
    let rec loop s i = 
    if i < n then loop (s + dir str.[i]) (i + 1) 
    else s in 
    loop 0 0 

循環的物化是一個fold功能。不幸的是OCaml標準庫中沒有String.fold函數。但是您可以使用由Janestreet生產的Core標準庫。具有fold功能,該循環可以表達得更加簡潔:

open Core_kernel.Std 

let count_parens str = 
    String.fold str ~init:0 ~f:(fun s c -> s + dir c) 
+0

...所以String.fold存在!很高興知道 ;) –

1

簡而言之,您應該使用fold而不是iter。由於標準字符串庫中沒有fold,因此您可能必須編寫自己的。

稍微長一點的答案是,您可能希望編寫一個遞歸函數,將累積和作爲其參數之一進行跟蹤。

0

使用參考:

let z = 
    let counter = ref 0 in (String.iter (fun (c: char) -> 
    counter := (!counter + dir c) 
) word); !counter;; 
+0

在這裏使用引用是反地道的。它隱藏了循環變體,並介紹了命令式編程的其他注意事項。而且,這是一種函數式編程語言,所以只要有可能,最好使用函數式方法。而且你不需要使用這麼多的括號,它們只會混淆代碼。 – ivg

+0

最初我想用String.fold這樣的東西,而不是使用引用。另一方面,即使在函數式編程中應避免引用您提到的原因,在目前的情況下,它會縮短代碼。 –