[.。oO(さっちゃん Advent Calendar) http://atnd.org/events/22829 ]10日目
今日はHaskell初心者以前のさっちゃんが、しぇらーしいさまの手になる以下のコードがなぜ動くのか読んでみたいとおもいます。あ、Opera忘年会で会ったら呼んでください。詠んでくださってもいいです>ω<
-- http://favstar.fm/users/shelarcy/status/130666089607725056 -- http://favstar.fm/users/shelarcy/status/142682424680259584 import System.IO (〃|_|) = \str -> hSetEncoding stdout utf8 >> hPutStrLn stdout str (.。) = ($) (oO) = id main = (〃|_|) .。oO("さっちゃん☆")
$ runghc momonga.hs さっちゃん☆
1行目
import System.IO
System.IOモジュールをimportしていますね。
2行目
(〃|_|) = \str -> hSetEncoding stdout utf8 >> hPutStrLn stdout str
関数定義ですね。左右に分けましょう。
(〃|_|) =
これは〃|_|
と云う名の関数を定義しています。()
で囲ってあるのは、英数文字じゃないからですね。そのまま書いてはparse errorに成ってしまいます。(+)などと同じですね。
|
も_
も全角ですが、特に全角である必要性は無い様です。ただ、途中に空白を空けてはなりません。parse errorが吐かれます。
\str -> hSetEncoding stdout utf8 >> hPutStrLn stdout str
\
は無名関数lambdaですね。strと云う引数をとる関数です。
関数本体は何でしょう? これはstrをコンソールに出力する処理です。コンソールに出力する処理ならば、putStrLn
があるのではないでしょうか? ghciで見てみましょう。
Prelude> :type putStrLn putStrLn :: String -> IO () Prelude> "さっちゃん☆" "\12373\12387\12385\12419\12435\9734" Prelude> putStrLn "さっちゃん☆" Uca▒▒
うわあああああああヾ(〃l _ l)ノ゙ Uca▒▒ってなんだぁ。どうやらputStrLn
はUnicode文字の出力はできないようです。ではhSetEncoding
とhPutStrLn
は何でしょう?
Prelude> :type (>>) (>>) :: Monad m => m a -> m b -> m b Prelude> import System.IO Prelude System.IO> :type hSetEncoding hSetEncoding :: Handle -> TextEncoding -> IO () Prelude System.IO> :type hPutStrLn hPutStrLn :: Handle -> String -> IO () Prelude System.IO> :type \str -> hSetEncoding stdout utf8 >> hPutStrLn stdout str \str -> hSetEncoding stdout utf8 >> hPutStrLn stdout str :: String -> IO ()
Handleにstdoutを指定して、TextEncodingのutf8を設定していますね。
>>
というのは、アクションを順次実行するよう繋ぐものです。アクションとは、たとえばIOの様な、副作用をともなう故に「関数」ではない奴等だそうです。
因みに瑣末ですがこれは、\str -> hSetEncoding stdout utf8 >> putStrLn str
でも同様に動作します。
3, 4行目
(.。) = ($) (oO) = id
$
とid
に別名を定義していますね。id
は恒等関数です。ではなぜ(.。oO) = ($)
ではダメなのでしょう? 実際これはparse errorになります。わからないのでパス。きっとUnicode文字関連です。
Prelude> :type id id :: a -> a Prelude> :type ($) ($) :: (a -> b) -> a -> b
$
は、関数の連鎖に近い見た目を作れる演算子(=関数)ですね。f $ a
で、fにaを部分適用します。Haskellでは全ての関数がカリー化(壱引数関数化)されていることの、威力ですね!
5行目
main = (〃|_|) .。oO("さっちゃん☆")
いよいよ文字列を出力するmain関数ですね。(〃|_|)
はString -> IO ()
でいいとして、別名は書き換えてみましょう。
main = (〃|_|) $ id "さっちゃん☆"
Prelude> :type ($)id ($)id :: b -> b
$ id
はid
と同じ型ですね。因みにこのコードは、main = (〃|_|) id "さっちゃん☆"
でも、main = (〃|_|) $ "さっちゃん☆"
でも、main = (〃|_|) "さっちゃん☆"
でも、同様に動作します。恒等関数ですからね!
こっちのコードも
もう読めますね! 型宣言がついているのみです。
-- http://favstar.fm/users/shelarcy/status/130666089607725056 import System.IO (〃|_|) :: String -> IO () (〃|_|) = \str -> hSetEncoding stdout utf8 >> hPutStrLn stdout str main = (〃|_|) "ももんが"
参考

Real World Haskell―実戦で学ぶ関数型言語プログラミング
- 作者: Bryan O'Sullivan,John Goerzen,Don Stewart,山下伸夫,伊東勝利,株式会社タイムインターメディア
- 出版社/メーカー: オライリージャパン
- 発売日: 2009/10/26
- メディア: 大型本
- 購入: 8人 クリック: 245回
- この商品を含むブログ (76件) を見る