F#のchar型は、テキストの、アドレス指定できる最小の構成要素を表す16ビットの値で、デフォルトでイミュータブルです。
charは、シングルクォートを使ったリテラルとして定義できます:
let ch = 'A'
// => val ch: char = 'A'
文字列はcharの並びです。
個々のcharは、0始まりのインデックスを使って文字列から取り出せます:
"Exercism"[4] // => 'c'
文字列を繰り返し処理すると、各ステップでcharが返されます。
次の例では、話を簡単にするために高階関数と匿名関数を使っています。 これらはシラバスの後半で詳しく扱いますが、今は文字列中の文字をループで処理するための、簡潔な書き方だと考えてください。
Seq.map (fun c -> c, int c) "F#" // => [('F', 70); ('#', 35)]
上で見たように、charはそのint値にキャストできます。
これは他の文字体系でも(少なくともある程度は)動作します:
Seq.map (fun c -> c, int c) "東京" // => [('東', 26481); ('京', 20140)]
文字を比較するときには、その基になっているInt16が使われます:
'A' < 'D' // => true
また、intをcharにキャストすることもできます:
char 77 // => 'M'
System.Charライブラリには、大文字・小文字の変換など、.NET言語で期待されるメソッドがひと通りそろっています:
'a' |> System.Char.ToUpper // => 'A'
'Q' |> System.Char.ToLower // => 'q'
この演習では、エンジニアが識別子の名前をきれいにするのを手助けする、ユーティリティルーチンの一部を実装します。
6つのタスクを通して、1文字を変換するtransform関数と、文字列を変換するclean関数を少しずつ作り上げていきます。
有効な識別子は、0個以上の英字、アンダースコア、ハイフン、疑問符、絵文字で構成されます。
clean関数に空文字列が渡された場合は、空文字列を返す必要があります。
transform関数を実装して、ハイフンをアンダースコアに置き換えます。
transform '-' // => "_"
すべての空白文字を削除します。先頭と末尾の空白も含まれます。
transform ' ' // => ""
transform関数を変更して、camelCaseをkebab-caseに変換します。
transform 'D' // => "-d"
transform関数を変更して、数字である文字をすべて省略します。
transform '7' // => ""
transform関数を変更して、'α'から'ω'までの範囲にあるギリシャ文字を置き換えます。
transform 'β' // => "?"
clean関数を実装して、これらの操作を文字列全体に適用します。
ルールに当てはまらない文字は、そのまま変更されずに通されます。
clean " a2b Cd-ω😀 " // => "ab-cd_?😀"
このトピックは、シラバスの後半で詳しく扱います。
今のところ、String.collectという高階関数があることを知っておくと役に立つでしょう。これを使うと、自分で用意した関数を使って、charのコレクションを文字列に変換できます。
let transform ch = $"{ch}_"
String.collect transform "abc" // => "a_b_c_"