2012-05-14 65 views
1

我是絕對的OCaml初學者,並且有一個關於更多代碼的任務。我有下面的代碼,但我不知道它是如何工作的。如果有人能幫助我,我很感激。OCaml代碼的解釋:爆炸一個字符串,拆分一個列表

# let explode str = (*defines function that explodes argument str witch is type 
         string into list of chars*) 
    let rec exp = function (*defines recursive function exp*) 
    | a, b when a < 0 -> b (*this part i dont know.is this pattern 
           matching ?is it function with arguments a and b 
           and they go into expression? when is a guard and 
           then we have if a is smaller than 0 then b *) 
(*if a is not smaller than 0 then this function ? *) 
    | a, b -> exp (a-1, str.[a]::b) (*this i dont know, a and b are arguments 
             that go into recursive function in the way 
             that a is decreesed by one and b goes into 
             string a?? *) 
    in   
    exp ((String.length str)-1, []);; (*defined function exp on string lenght of 
             str decresed by one (why?) [ ]these 
             brackets mean or tell some kind of type ? *) 

# let split lst ch = 
    let rec split = function (* defines recursive fun split *) 
    | [], ch, cacc', aacc' -> cacc'::aacc'(* if empty ...this is about what i got 
              so far :) *) 
    | c::lst, ch, cacc', aacc' when c = ch -> split (lst, ch, [], cacc'::aacc') 
    | c::lst, ch, cacc', aacc' -> split (lst, ch, c::cacc', aacc') 
    in 
    split (lst, ch, [], []);; 

val split : 'a list -> 'a -> 'a list list = <fun> 
+0

你爲什麼不加註釋的代碼說明你已經瞭解它,說明你不理解的部分開始? – eggyal

+0

我已經做到了。 – user1393318

回答

3

此代碼是醜陋的。誰一直在給你的是讓你失望。如果我的一個學生寫了這樣的話,我會讓他們在不使用when條件的情況下重寫它們,因爲它們往往會令人困惑,所以鼓勵在沒有保證的地方編寫模式匹配的代碼。
作爲一個大拇指的規則,初學者不應該使用when。簡單的if..then..else測試可提高可讀性。

下面是這兩個函數,改寫可讀性相當於版本:

let explode str = 
    let rec exp a b = 
    if a < 0 then b 
    else exp (a - 1) (str.[a] :: b) 
    in 
    exp (String.length str - 1) [] 

let split input delim_char = 
    let rec split input curr_word past_words = 
    match input with 
     | [] -> curr_word :: past_words 
     | c :: rest -> 
     if c = delim_char 
     then split rest [] (curr_word :: past_words) 
     else split rest (c :: curr_word) past_words 
    in 
    split input [] [] 

我的意見,瞭解他們是自己運行它們,就給出了一個實例,在紙面上。只需寫下函數調用(例如,explode "foo"split 'b' ['a';'b';'c';'d']),展開定義,評估代碼以獲取另一個表達式等,直到獲得結果。這裏是一個例子:

explode "fo" 
=> 
exp (String.length "fo" - 1) [] 
=> 
exp 1 [] 
=> 
if 1 < 0 then [] else exp 0 ("fo".[1] :: []) 
=> 
exp 0 ("fo".[1] :: []) 
=> 
exp 0 ('o' :: []) 
=> 
exp 0 ['o'] 
=> 
if 0 < 0 then ['o'] else exp (-1) ("fo".[0] :: ['o']) 
=> 
exp (-1) ("fo".[0] :: ['o']) 
=> 
exp (-1) ('f' :: ['o']) 
=> 
exp (-1) ['f'; 'o'] 
=> 
if -1 < 0 then ['f'; 'o'] else exp (-2) ("fo".[-1] :: ['o']) 
=> 
['f'; 'o'] 

要小心這樣做,對於每個功能,以及任何功能,你將有問題的理解。在一個小例子上。這是獲得關於發生的事情的最佳方式。 (稍後,當你變得更習慣於遞歸時,你會發現你實際上並不需要那樣做,你可以對函數進行歸納推理:假設他們做了什麼,並且假設遞歸調用實際上是這樣做的,檢查它是否確實做到了這一點,在更高級的情況下,試圖將所有的執行都放在頭腦中是太難了,這種感應技術效果更好,但它更高層次,需要更多實踐。首先通過簡單地運行代碼開始。)

+0

謝謝你的回答,你很善良。我會知道你的建議 – user1393318

0

你也可以用這種方式實現。

let rec strexp s = 
    if length(s)==0 then 
    [] 
    else 
    (strexp (sub s 0 (length(s)-1)))@(s.[length(s)-1]::[])  
;; 
1

如果您正在使用的核心庫,你可以只使用

String.to_list "BKMGTPEZY" 

如果你想字符串將返回的chars名單只是map它:

String.to_list "BKMGTPEZY" |> List.map ~f:Char.to_string 

輸出:

- : bytes list = ["B"; "K"; "M"; "G"; "T"; "P"; "E"; "Z"; "Y"] 

作爲一個功能

let explode s = String.to_list s |> List.map ~f:Char.to_string