Char

Char 型は、Unicode 文字を表します。二重引用符 " ではなくてシングルクォート ' で囲んで表されます。

-- Char はシングルクォートで囲む #check ('a' : Char) #check ("a" : String) -- Unicode 文字を含む #check ('あ' : Char) #check ('∀' : Char) #check ('∅' : Char)

符号位置

Char は、以下のように structure として定義されています。

structure Char where /-- Unicode スカラー値 -/ val : UInt32 /-- `val` が正しく Unicode の code point であること -/ valid : val.isValidChar

したがって Char.val 関数により 符号位置(code point) を取得することができます。

#guard 'a'.val = 97 #guard '⨅'.val = 10757

これを利用すると、たとえば「アルファベットを与えられた整数 n だけずらして暗号化する関数」を以下のように実装することができます。1

/-- アルファベットのインデックス -/ structure Index where /-- 番号。`0`から`25`の数字 -/ index : Nat /-- 小文字かどうか -/ isLower : Bool deriving Inhabited, DecidableEq /-- アルファベットを`Index`に変換する -/ def Char.toIndex (c : Char) : Index := if c.isLower then ⟨c.val - 'a'.val |>.toNat, trueelse if c.isUpper then ⟨c.val - 'A'.val |>.toNat, falseelse panic! s!"toIndex: input is {c}, which is not an alphabet" #guard 'a'.toIndex = ⟨0, true#guard 'B'.toIndex = ⟨1, false/-- インデックスをアルファベットに変換する -/ def Char.ofIndex (i : Index) : Char := Id.run do if i.index > 25 then panic! s!"ofIndex: index is out of range: {i.index} > 25." if i.isLower then Char.ofNat ('a'.val.toNat + i.index) else Char.ofNat ('A'.val.toNat + i.index) #guard Char.ofIndex ⟨0, true⟩ = 'a' #guard Char.ofIndex ⟨1, false⟩ = 'B' /-- アルファベットを`n`だけシフトする -/ def Char.shift (c : Char) (n : Int) : Char := if c.isAlpha then let code := (c.toIndex.index + n) % 26 |>.toNat let index : Index := ⟨code, c.isLower⟩ Char.ofIndex index else c #guard Char.shift 'a' 3 = 'd' #guard Char.shift 'z' 3 = 'c' #guard Char.shift 'B' (-3) = 'Y' /-- シーザー暗号の実装。文字列に登場する文字をシフトする。 -/ def String.encode (s : String) (n : Int) : String := s.map (Char.shift · n) #guard "I am a magician.".encode 3 = "L dp d pdjlfldq." #guard "L dp d pdjlfldq.".encode (-3) = "I am a magician."
1

この例は、Graham Hutton「プログラミングHaskell第2版」(ラムダノート)第5章を参考にしています。