1

私は絶対的な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>
4

3 に答える 3

4

このコードは醜いです。あなたにそれを与えてきた人は誰でも、あなたに不利益をもたらしています。私の学生がそれを書いた場合、when条件分岐を使用せずに書き直すように依頼します。それらは混乱を招く傾向があるためです。保証されていない場所でパターン マッチングを多用するコードを記述することをお勧めします。
経験則として、初心者は決して使用しないでくださいwhen。簡単なif..then..elseテストにより、可読性が向上します。

読みやすくするために書き直した、これら 2 つの関数の同等のバージョンを次に示します。

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"and 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']

各関数、および理解に問題のある関数について、これを行うように注意してください。小さな例で。これは、何が起こっているかをグローバルに把握するための最良の方法です。

(後で再帰に慣れると、実際にはそれを行う必要がないことがわかります。関数について帰納的に推論できます。関数が何をするかを仮定し、再帰呼び出しが実際にそれを行うと仮定します。より高度なケースでは、頭の中ですべての実行を保持しようとするのは非常に困難であり、この誘導手法はよりうまく機能しますが、より高度であり、より多くの練習が必要です.コードを実行します。)

于 2012-05-14T13:06:18.440 に答える
1

Core ライブラリを使用している場合は、次を使用できます

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
于 2015-04-05T23:24:45.353 に答える
0

この方法で実装することもできます。

let rec strexp s  =  
  if length(s)==0 then 
   []
  else
  (strexp (sub s 0 (length(s)-1)))@(s.[length(s)-1]::[])    
;;
于 2014-04-10T14:50:08.830 に答える