Let's start Scheme

2014-05-09

SRFI-14の紹介

(LISP Library 365参加エントリ)

SRFI-14は文字セットを扱うSRFIです。このSRFIは他のSRFIの下請け的に使われることが念頭にあります(Abstract参照)。実際SRFI-13にはSRFIを使っている部分があります。

基本的な使い方を見てみましょう。
(import (srfi :14))

(char-set-contains? char-set:digit #\a)
;; -> #f

(char-set-contains? char-set:digit #\1)
;; -> #t
基本はこれだけです。一応セットなので以下のようにセットに登録されている文字を扱うことも可能です。
(char-set-map char-upcase char-set:lower-case)
;; -> charset with #\A-#\Z range
ただ、上記のような手続きを日常的に使うということはまずないでしょう。新たに文字セットを構築するのであれば以下の手続きの方がはるかに便利です。
(list->char-set '(#\a ...))
;; -> charset with given chars

(string->char-set "abc..."))
;; -> charset contains given string's characters

(ucs-range->char-set #x100 #x10FFFF)
;; -> charset with range 0x100-0x10FFF
既存の文字セットものから文字を追加もしくは削除ということも可能です。
(char-set-adjoin char-set:letter #\-)
;; -> charset with letters (#\a-#\z #\A-#\Z) + #\-

(char-set-delete char-set:digit #\0)
;; -> charset of #\1-#\9
上記の手続きには破壊的に操作を行うものも用意されています。

これだけだとちょっと寂しいので多少実装にも踏み込んでみます。SRFI-14は参照実装も用意されていますが、参照実装では最大でLatin-1までの範囲しかサポートされていません。実装もかなり素朴で、char-set-containsは256までしかないことを利用したO(1)の手続きです。(ちなみに反復子的な手続きは逆に256回反復させます。)

これはLatin-1までの範囲に絞っているから可能なのであって、Unicodeをサポートするのであれば不可能な実装とも言えます。(ハッシュテーブルのエントリを2^32個作るのは現実的ではないでしょう。) セットが含む文字を全て舐めるO(n)の実装でもまぁ問題はないのかもしれないですが、二分木辺りを使ってO(log(n))くらいで抑えられるといいかもしれません。(疎な配列を使ったO(1)とかも実装によって現実的かも。ただエントリが増えるとハッシュテーブルと同じ問題が起きる?)

今回はSRFI-14を紹介しました。

No comments:

Post a Comment