2015-12-08 2 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

Loops в 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. Но вы можете использовать стандартную библиотеку Core, выпускаемую Janestreet. С помощью функции 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. Поскольку в стандартной библиотеке String нет fold, вам, возможно, придется написать свой собственный.

Несколько более длинный ответ заключается в том, что вы, вероятно, захотите написать рекурсивную функцию, которая отслеживает кумулятивную сумму как один из ее параметров.

0

Использование ссылки:

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

Использование ссылок здесь встречно-идиоматическое. Он скрывает варианты цикла и вводит другие предостережения о императивном программировании. Кроме того, это функциональный язык программирования, поэтому лучше использовать функциональный подход, когда это возможно. И вам не нужно использовать столько скобок, они только загромождают код. – ivg

+0

Первоначально я хотел использовать sth как String.fold, а не использовать ссылку. С другой стороны, даже если ссылки следует избегать в функциональном программировании по той причине, о которой вы говорите, в текущем случае это делает код короче. –

Смежные вопросы