2012-03-25 12 views
8

文字列を渡して、逆の文字列を取得しようとしました。なぜ私はこれをすることができません:文字列のOCaml関数のパラメータパターンマッチング

let rec reverse x = 
    match x with 
    | "" -> "" 
    | e^s -> (reverse s)^e;; 

コンパイラは、それは構文エラーだと言います。パラメータを分解するのに^を使用できませんか?

+0

:ここ

され、ヘルパーメソッドと一緒にexplodeimplodeを文字列にコンパイラにも文字列を分割する必要がありますか? "abc"から "a" "bc"または "ab" "c" – 0x434D53

答えて

15

これは、文字列がリストと同じようにデータ型として表現されないためです。したがって、cons(::)はコンストラクタですが、^はではなく、です。代わりに、文字列は再帰的な定義なしで(リストのように)下位レベルの型として表現されます。文字列を文字のリストとして照合する方法があります.SMLの関数(OCamlで書くことができます)は 'explode'と 'implode'と呼ばれ、文字列をcharリストに取り込みます。 。 Here's an example implementation of them.

+0

ありがとうございます。しかし、とにかくC++のようなオペランドを「オーバーロード」するのはどうですか?それは間違いなく抽象概念を改善するでしょう。 – lkahtz

+1

いいえ、オペレータを過負荷にする方法はありません。文字列は下位レベルの型として定義されており、基本的には誘導的に定義された型ではないため、人工的にデータ型に指定することはできません。 –

1

パターンマッチング式を記述するとき、パターンに任意の関数を使用することはできません。 のコンストラクタは、と評価されていません関数のみ使用できます。例えば、関数 "+"は整数に定義されています。したがって、式1+2が評価され、3が得られます。関数 "+"が評価されるので、x+yで一致することはできません。数値がゼロかどうかをチェックする自然数に関数を定義しようとしています:

let f x = match x with 
    | 0 -> false 
    | a+1 -> true 
;; 

これは機能しません!同じ理由で、文字列を使ったあなたの例は動作しません。関数 "^"は文字列で評価され、コンストラクタではありません。は、評価されていない演算子+と記号定数1からの評価されていない記号式である場合にのみ機能します。の一致は、これはOCAMLのケースではありません。整数はマシン番号で直接実装されます。

バリアント型にマッチすると、未評価の式であるコンストラクタと一致します。たとえば:'a option型は、このようなSome xとして、シンボリック式から作られているので

# let f x = match x with 
    | Some x -> x+1 
    | None -> 0 
;; 
val f : int option -> int = <fun> 

これは動作します。ここでは、Someは評価され、他の値を与える関数ではなく、評価されない関数と考えることができる「コンストラクタ」です。式Some 3はそれ以上評価されません。それはそのままです。このような関数でのみ、パターンマッチングが可能です。

リストは、コンストラクタで構築されたシンボリックで未評価の式です。コンストラクタは::です。 x :: y :: []の結果は未評価の式であり、化粧の便宜のためにリスト[x;y]で表されます。このため、リストのパターンマッチングが可能です。

+0

あなたの答えをありがとう。 OCamlで文字列のパターンマッチングが可能かどうか、またどのようにパターンマッチングができるかを言えばうれしいでしょう。 –

1

Kristopher Micinski explainedとすると、リストではないため、文字列のパターンマッチングはできません。

ただし、explodeを使用してリストに変換できます。

let rec reverse str = 
    match explode str with 
    [] -> "" 
    | h::t -> reverse (implode t)^string_of_char h 

はこのようにそれを使用してください:ここでexplodeimplodeその対応を用いたパターンマッチングを使用してreverse機能があります、それは、マルチバイトのもののために、シングルバイト文字の作品ではなく、ことを示して

let() = 
    let text = "Stack Overflow ♥ OCaml" in 
    Printf.printf "Regular: %s\n" text; 
    Printf.printf "Reversed: %s\n" (reverse text) 

。以下の説明のためにさらに

let string_of_char c = String.make 1 c 

(* Converts a string to a list of chars *) 
let explode str = 
    let rec explode_inner cur_index chars = 
    if cur_index < String.length str then 
     let new_char = str.[cur_index] in 
     explode_inner (cur_index + 1) (chars @ [new_char]) 
    else chars in 
    explode_inner 0 [] 

(* Converts a list of chars to a string *) 
let rec implode chars = 
    match chars with 
    [] -> "" 
    | h::t -> string_of_char h^(implode t)