tr コマンドもどき。文字列中の文字を置き換える。
import Data.List tr _ _ [] = [] tr str1 str2 (c:cs) = (tr' str1 str2 c):(tr str1 str2 cs) where tr' str1 str2 c = case (elemIndex c str1) of Just n -> str2 !! n Nothing -> c
キモは elemIndex の返り値。elemIndex は文字列 str1 中の文字 c のインデックス(0から始まる)を返す関数だけど,返り値の型が Int じゃなくて Maybe Int なので,case で場合分けをしている。はじめこの返り値の型に気づかなくて悩んでしまった。こういうのは真っ先に確認すべきだな。
*Main> :type elemIndex elemIndex :: (Eq a) => a -> [a] -> Maybe Int
結果。
*Main> tr "ab" "AB" "banana" "BAnAnA"
ところで,引数に文字列を3つとるのはいいけどその名前が str1,str2 っていうのは我ながらどうかと思う。こういうのってセンスが問われるよなぁ。
追記:
再帰じゃなくて map を使うようにした。ついでに引数の名前を短く。
import Data.List tr _ _ [] = [] tr s1 s2 str = map (tr' s1 s2) str where tr' s1 s2 c = case (elemIndex c s1) of Just n -> s2 !! n Nothing -> c
さらに追記:
tr’ の引数を省略。ちょっとすっきりした。こうやって where 節で局所定義された関数から外側の関数の引数を直接参照できるのっておもしろいねぇ。
import Data.List tr _ _ [] = [] tr s1 s2 str = map tr' str where tr' c = case (elemIndex c s1) of Just n -> s2 !! n Nothing -> c
*Main> tr "ab" "AB" "banana" "BAnAnA"
こんなのはどうでしょう。これならPreludeの関数だけでいけます。
tr :: String -> String -> String -> String
tr from to = map f
where
f c = case lookup c tbl of Nothing -> c; Just c’ -> c’
tbl = zip from to
ふーむ。置き換える前後の文字のペアを作っておくのか。assoc list ってヤツですね。
こんなの書いてみました。
http://oss.timedia.co.jp/index.fcgi/kahua-web/show/ossz/oneline/2006-04-28 2006-04-28