Haskellのお題

昨日は、暑い中を走り回った自分へのご褒美として、シフォンケーキを買ってきた。 普通、暑いと言えば そりゃ、ビールだろうと なる訳だが、昼間からビールを飲む のもちょっとはばかられるので控えました。(時と場合によりますが ...)

で、ケーキを冷蔵庫でギンギンに冷やしてから食べたら、シフォンケーキに大量に 含まれる空気も冷えていて、ほど良い冷気が口中に広がり、オツなものでした。

2CH から Haskell のお題

と、書くと、いつも2CHに入り浸っているように思われますので、 あの方も悩んでいる という事で、一緒に悩みましょう。

関数型プログラミング言語Haskell Part10 [bbs2chreader]
495 デフォルトの名無しさん [sage] Date:2009/05/20(水) 11:20:05  ID: Be:
    入力されたテキストの、行頭の1つ以上連続した半角スペースを
    同じ数の半角の   という文字列に置き換える
    …ってHaskellで書くとどうなりますか 

これ、宿題なんでしょうか? 良問っぽくて、てんで分かりませんでした。正規表現で 書けるんでしょうか? s/^ +/&nbsps;/g は、g等を付けて、気持ちは分かるけど、違い ますね。Haskellでの回答は、

496 デフォルトの名無しさん [sage] Date:2009/05/20(水) 12:23:58  ID: Be:
    main = interact $ unlines . map processLine . lines

    processLine :: String -> String
    processLine ln = nbsps ++ rest
      where
        (ws, rest) = span (==' ') ln
        nbsps = concat $ map (const " ") ws 

回答、早いですねぇ。その場で即答されたんでしょうか? Haskell脳の人は凄いなあ。 私なぞは、一旦別言語で考えてから、置き換えてゆくぐらいの事しか出来ません。

main行は、定型句だから良いとして、問題は、processLineですね。ちょっと実験してみます。

*Main> processLine "  abcdefg"
"  abcdefg"

冒頭が、  に、なっていないです。じっと見つめると、const ってのが怪しい。 名前からして、定数を返すようだけど、辞書を引いて調べてみます。

*Main> :info const
const :: a -> b -> a 	-- Defined in GHC.Base
*Main> const "foo" "bar"
"foo"

2引数のうちの、最初の方を返してくれるのね。そうすると、" " は、本来は "&nbsps;"のはずだけど、抽象化しちゃってるんだ。次に分からない単語は、spanだ。これも辞書で調べてみます。

*Main> :i span
span :: (a -> Bool) -> [a] -> ([a], [a]) 	-- Defined in GHC.List
*Main> span (== 'a') "abcd"
("a","bcd")
*Main> span (== 'a') "aaaBCDEF"
("aaa","BCDEF")
*Main> span (== 'x') "abcd"
("","abcd")
*Main> span (/= 'c') "abcd"
("ab","cd")

大体言わんとしてる事は分かりましたが、この際ですから英英辞書も引いてみます。

-- | 'span', applied to a predicate @p@ and a list @xs@, returns a tuple where
-- first element is longest prefix (possibly empty) of @xs@ of elements that
-- satisfy @p@ and second element is the remainder of the list:
-- 
-- > span (< 3) [1,2,3,4,1,2,3,4] == ([1,2],[3,4,1,2,3,4])
-- > span (< 9) [1,2,3] == ([1,2,3],[])
-- > span (< 0) [1,2,3] == ([],[1,2,3])
-- 
-- 'span' @p xs@ is equivalent to @('takeWhile' p xs, 'dropWhile' p xs)@

span                    :: (a -> Bool) -> [a] -> ([a],[a])
span _ xs@[]            =  (xs, xs)
span p xs@(x:xs')
         | p x          =  let (ys,zs) = span p xs' in (x:ys,zs)
         | otherwise    =  ([],xs)

文字による分割だけじゃなくて、いろいろと応用出来るのね。勉強になります。 さて、これで知らない単語は無くなった(はず)。後は、どう解釈するかだな。

都合よく考えると、行は、行頭から連続した部分(nbsps)とそれ以外(rest)を連結して 出来ている(と、宣言したよ)

そんじゃ、スペースの連続とそれ以外の部分の2つに分けてあげよう。そんな便利な 関数は、spanがあるじゃん。分けた部分に、名前を付けておこう(ws, rest)。 wsは、スペースの連続になっているんで、1スペースについて、&nbsps;に変換してから そいつを、くっつければいいよ。そいつは、nbspsだ。 やっと、日本語に翻訳できました。疲れました。

音から派生して ...

私が買った、音本は、去年オーム社から出版された 「C言語ではじめる 音のプログラミング」なんて言う本である。かの人によると、去年はC関係の本が26冊出たそうである。 Ruby本は去年はラッシュであったが、バブルに終るのだろうか?

音本をぱらぱらとめくってゆくと、当然のごとく フィルターなんてのが出てくる。 フィルターを実用的にやろうとすると、DSPの世界へと突入せざるを得ない。

DSPでいろいろ探していたら、面白いページに行きあたった。

Blackfin空挺団さんの所に、昔やったアマチュア無線関係の楽しい話題がたくさんある。

昔は、SSB通信をやりたくても、クリスタルフィルターなんて高くて、とても買えないし、苦肉の策で、PSNネットワーク+ダブルバランスドミクサーで、サイドバンドが洩れ洩れのもどきをやったものです。

今なら、楽しい事がいっぱいできて、面白いなあ。