2011年12月19日月曜日

Pandoc で Blogger の記事を書く

Pandoc で 様々なフォーマットの文書を作成する

tanakhさんの記事で、Pandoc という Haskell 製の文書フォーマット変換ツールがあることを知りました。私は、Emacs + SKK で文書を書くのが最もストレスが低いので、Emacsで文書を書いて、他のフォーマットに変換できると非常に幸せです。とりあえず、Blogger の Blog 記事を書くときの Pandoc の活用方法についてメモしておきます。

インストール

> cabal install pandoc -fhighlighting
-fhighlighting でシンタックスハイライト機能を有効にしておきます。

使いかた

Pandoc のページ を見ると、Markdown, reStructuredText 等の様々なフォーマットから HTML, PDF, ... 等の多様なフォーマットに変換できることが書いてあります。
とりあえず、"Markdown 形式で文書を書いて、HTMLに変換し、Blogger の記事にする" という目的で使います。
この記事も勿論, Markdown で書いています。

変換のしかた

> pandoc markdown_file.txt -o output.html
で Markdown -> HTML に変換できます。

Markdown の文法

ココ(DALING FIREBALL)や, ココ(Wikipedia) が参考になるでしょう。

Haskell のソースを Syntax Highlighting する

Haskell のソースを Syntax Hilighting する方法を書きます。(そもそもコレをメモしたかったので、この記事を書きました)
通常、Markdown で program source を書くには、先頭に4文字以上の空白を入れてインデントすればいいみたいですが、これでは Syntax Highlight してくれないようです。また、私は空白でインデントする書き方が好きではありません。
ココに情報がありますが、ソースコード等を書くには
~~~~~~
source code here
~~~~~~
のように、tilde 6 個以上で囲んで、その間に書けばいいみたいです。
Haskell のコードを Syntax Highlight するには、
~~~~~~{.haskell}
hoge::[Char]->Int
hoge (x:xs) = undefined
~~~~~~
のように、上の行を ~~~~~~{.haskell} にすればいいみたいです。 行番号を入れるには、
1
2
3
4
~~~~~~{.haskell .numberLines}
hoge::[Char]->Int
hoge (x:xs) = undefined
~~~~~~
のように、上の行を ~~~~~~{.haskell .numberLines} にすればいいみたいです。
これを html に変換して Blogger の記事に貼ればよいのですが、色の部分は css で実現されているため、css を変更しないと色が付きません。
Blogger のテンプレートの カスタム css の部分に、以下の css を追加します。 (pandoc -s file.txt -o html で出力した HTML の
の部分から抽出したものです)
table.sourceCode, tr.sourceCode, td.lineNumbers, td.sourceCode, table.sourceCode pre 
   { margin: 0; padding: 0; border: 0; vertical-align: baseline; border: none; }
td.lineNumbers { border-right: 1px solid #AAAAAA; text-align: right; color: #AAAAAA; padding-right: 5px; padding-left: 5px; }
td.sourceCode { padding-left: 5px; }
code.sourceCode span.kw { color: #007020; font-weight: bold; } 
code.sourceCode span.dt { color: #902000; }
code.sourceCode span.dv { color: #40a070; }
code.sourceCode span.bn { color: #40a070; }
code.sourceCode span.fl { color: #40a070; }
code.sourceCode span.ch { color: #4070a0; }
code.sourceCode span.st { color: #4070a0; }
code.sourceCode span.co { color: #60a0b0; font-style: italic; }
code.sourceCode span.ot { color: #007020; }
code.sourceCode span.al { color: red; font-weight: bold; }
code.sourceCode span.fu { color: #06287e; }
code.sourceCode span.re { }
code.sourceCode span.er { color: red; font-weight: bold; }
これで、上記の Markdown を変換した HTML を記事に貼れば、シンタックスハイライトされます。

2011年12月18日日曜日

Haskell で parser を書くには (初心者編)

Haskell で parser を書くには (初心者編)

勝手に Haskell Advent Calendar 2011

Haskell Advent Calendar 2011 にはエントリーできませんでしたけど、一人寂しく「勝手に Haskell Advent Calendar 2011」を開催して、わくわくクリスマスを待ちたいと思います。

目的:

Parsec3 と attoparsec の基本的使用法, Applicative スタイルを習得する

前置き:

Haskell で parser を書くにはどうすればいいのでしょうか? 私は、これを勉強すべく情報源を探しましたが、一体どこからどう始めればいいのか分からず、非常に混乱しました。「この記事を読めば大体概要が全部分かる」という情報源が日本語でも英語でも見つけられなかったからです。なので自分でまとめてみることにしました。 (私は、まだ Haskell 初心者+αのレベルで、parser の情報も現時点での情報ということをご理解ください)
私が混乱したのは、以下のような情報に出会ったからです。
  • Programming In Haskell に書いてある parser は、本の中のコードのみでは動かない
  • Haskell で parser を書くには、Parsec を使うとよいらしい
  • Parsec2 は使うな。Parsec3 使え。
  • Real World Haskell は Parsec2 で記述されているので古い
  • Parsec は遅い。attoparsec は速い。
  • attoparsec は、エラーメッセージが不親切
???。一体どうすればいいのでしょうか? Parsec はいいの?ダメなの? attoparsec はいいの?ダメなの? 最良の選択肢は、どれなの??
勉強会で質問してみた結果、以下のように理解しました。
  • デファクトスタンダードが どれか一つ というわけではなく、皆さんは "Parsec3" と "attoparsec" を使い分けているようだ
  • Parsec3 は attoparsec より速度は遅いが、エラーメッセージが親切
  • attoparsec は Parsec3 より速度は速いが、エラーメッセージが不親切
  • ニーズに応じて Parsec3 と attoparsec を使い分ける(もしくは両方使う)のがオススメ。でも、Parsec2 は古いので使わないことをオススメ
やっと状況が分かりました。Parsec3 と attoparsec を理解すればいいようです。しかし、それでも まだ困惑は残りました。なぜなら、Parsec3 と attoparsec の初心者向けの、よい Tutorial 記事を見つけられなかったからです。
この記事では、「Parsec3 と attoparsec の基本的な書きかたを理解する」ことを目的とします。副産物として、Applicative スタイルというのに触れます。
順番としては、以下の順番で書きます。
  • (1): 簡単な BNF を定義する
  • (2): Parsec3 で、(1) を解析してみる
  • (3): (2) を Applicative スタイルにする
  • (4): (3) を attoparsec に移植する
  • (5): さらに勉強するための情報源
尚, 内容のほとんどは、kazu-yamamoto さんの記事 を参考にさせていただいてます。(kazu さん ありがとうございます)

(1): 簡単な BNF を定義する

プログラミング Haskell の 8章の内容を多少簡単化して、 "1ケタの数字の加算と乗算ができるパーサー" を題材にします。BNF は以下です。
1
2
3
4
expr ::= term '+' expr | term
term ::= factor '*' term | factor
factor ::= '(' expr ')' | nat
nat ::= '0' | '1' | '2' | ...
1ケタの数値のみしか扱えませんが、()が使え、乗算が加算より優先順位が高く、'+','*'は右結合になっています。

(2): Parsec3 で、(1) を解析してみる

上記 (1) のBNF を解析し、data Exp 型の結果を返す parser を Parsec3 で実装します。Parsec3 を使うには
1
2
import Text.Parsec
import Text.Parsec.String
します。 次に、BNF の定義を Haskell のコードに対応させて実装していきます。BNF で、選択を意味する '|' は、Haskellでは、Text.Parsec.(<|>) という二項演算子です。 (本:プログラミングHaskell では、(+++) と記述されています) 一文字の記号 '+', '*' を parse するには
1
char c
を使います。文字が、複数の文字リスト(ex:数字列)のどれかにマッチすればよい場合は、
1
oneOf [Char]
を使います。 ParsecSample1.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
import Data.Char (ord)
import Text.Parsec (char, oneOf, (<|>), parseTest)
import Text.Parsec.String (Parser)

data Exp = Add Exp Exp | Mul Exp Exp | Nat Int deriving Show
{- BNF of one digit addtion & multiplication
expr ::= term ('+' expr | ε)
term ::= factor ('*' term | ε)
factor ::= '(' expr ')' | nat
nat ::= '0' | '1' | '2' | ...
-}

-- expr ::= term ('+' expr | ε)
expr::Parser Exp
expr = 
  do 
    t <- term
    do
      char '+'
      e <- expr
      return (Add t e)
     <|> return t

-- term ::= factor ('*' term | ε)
term::Parser Exp
term = 
  do
    f <- factor
    do
      char '*'
      t <- term
      return (Mul f t)
     <|> return f

-- factor ::= '(' expr ')' | nat
factor::Parser Exp    
factor = 
  do
    char '('
    e <- expr
    char ')'
    return e
   <|> nat

-- nat ::= '0' | '1' | '2' | ...
nat::Parser Exp
nat = 
  do
    c <- oneOf ['0'..'9']
    return (Nat (charToInt c))
  where
    charToInt c = ord c - ord '0'

{- How to test this
parseTest expr "1+2*3"
parseTest expr "(1+2)*3"
-}
do の後に、素直に BNF の個々の定義を並べて処理して行けばよいのですが、ちょっと読みにくいですね(このままだと、「BNFをそのまま実装できる」は、ちょっと言い過ぎな感じ)。 動作をテストするには、ghci にロードして
1
2
parseTest expr "1+2*3"
parseTest expr "(1+2)*3"
等で解析結果を確認できます。

(3): (2) を Applicative スタイルにする

Applicative スタイル にすると、もっと簡潔に記述できます。やってみましょう。
ParsecSample2.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import Control.Applicative ((<$>),(*>),(<*),pure)
import Data.Char (ord)
import Text.Parsec (char, oneOf, (<|>), parseTest)
import Text.Parsec.String (Parser)

data Exp = Add Exp Exp | Mul Exp Exp | Nat Int deriving Show
{- BNF of one digit addtion & multiplication
expr ::= term ('+' expr | ε)
term ::= factor ('*' term | ε)
factor ::= '(' expr ')' | nat
nat ::= '0' | '1' | '2' | ...
-}

-- expr ::= term ('+' expr | ε)
expr::Parser Exp
expr = 
  do 
    t <- term
    (Add t <$> (char '+' *> expr)) <|> pure t

-- term ::= factor ('*' term | ε)
term::Parser Exp
term = 
  do
    f <- factor
    (Mul f <$> (char '*' *> term)) <|> pure f    

-- factor ::= '(' expr ')' | nat
factor::Parser Exp    
factor = (char '(' *> expr <* char ')') <|> nat

-- nat ::= '0' | '1' | '2' | ...
nat::Parser Exp
nat = Nat . charToInt <$> oneOf ['0'..'9']
  where
    charToInt c = ord c - ord '0'

{- How to test this
parseTest expr "1+2*3"
parseTest expr "(1+2)*3"
-}
ぐっと短くなりましたね。これなら BNF を、そのまま Haskell コードに実装できると言っても過言ではなさそうです。 Applicative スタイルの詳細は、kazu さんの記事を参照していただくとよいですが、
  • pure は return と同じ (値を返り値の型に wrap する)
  • (<$>) は fmap (文脈に持ち上げる)
  • (*>) は左の処理結果を捨てて連結
  • (<*) は右の処理結果を捨てて連結
という意味のようです(私も勉強中...。)

(4): (3) を attoparsec に移植する

なんとか Parsec3 を使って簡単な BNF を Haskell で解析できるようになりました。でも、attoparsec も使ってみたいです。やってみましょう。
1
cabal install attoparsec
等で適当にインストールしてください(省略)。 attoparsec を使うには、先程の Parsec3 の import の変わりに、以下を記述します。
1
2
import Data.Attoparsec.Text
import Data.Text
attoparsec は String ではなくて、ByteString と Text を parse するようです。ここでは、Data.Text を使います。
もしかして、import を変えれば、そのまま動いたりして、、と思ったのですが、Parsec3 にあった oneOf という関数が無いようです。attoparsec の satisfy 関数を使ってテキトーに作ります。
1
2
oneOf::[Char]->Parser Char -- attoparsec には oneOf がないので自作
oneOf xs = satisfy $ flip elem $ xs
ここだけ変更すれば、そのまま行けそうです。
AttoparsecSample1.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
import Control.Applicative ((<$>),(*>),(<*),pure,(<|>))
import Data.Char (ord)
-- import Text.Parsec (char, oneOf, (<|>), parseTest)
-- import Text.Parsec.String (Parser)
import Data.Attoparsec.Text (char, Parser, parseTest, satisfy)
import Data.Text (pack)

oneOf::[Char]->Parser Char -- attoparsec には oneOf がないので自作
oneOf xs = satisfy $ flip elem $ xs

data Exp = Add Exp Exp | Mul Exp Exp | Nat Int deriving Show
{- BNF of one digit addtion & multiplication
expr ::= term ('+' expr | ε)
term ::= factor ('*' term | ε)
factor ::= '(' expr ')' | nat
nat ::= '0' | '1' | '2' | ...
-}

-- expr ::= term ('+' expr | ε)
expr::Parser Exp
expr = 
  do 
    t <- term
    (Add t <$> (char '+' *> expr)) <|> pure t

-- term ::= factor ('*' term | ε)
term::Parser Exp
term = 
  do
    f <- factor
    (Mul f <$> (char '*' *> term)) <|> pure f    

-- factor ::= '(' expr ')' | nat
factor::Parser Exp    
factor = (char '(' *> expr <* char ')') <|> nat

-- nat ::= '0' | '1' | '2' | ...
nat::Parser Exp
nat = Nat . charToInt <$> oneOf ['0'..'9']
  where
    charToInt c = ord c - ord '0'

{- How to test this
parseTest expr "1+2*3"
parseTest expr "(1+2)*3"

parseTest expr $ pack "1+2*3 "
parseTest expr $ pack "(1+2)*3 "
※ 最後にスペースがないと、成功していても "Partial _" という出力になる
-}
ghci に load してテストしてみましょう。
1
parseTest expr "1+2*3"
うまく行きませんね。あ、String じゃなくて、Text にしないとダメだったかな? pack で String->Text にしてみます。
1
2
> parseTest expr $ pack "1+2*3"
Partial _
あれ、"Partial _" とか言われますね。うまく行ってないのだろうか??? ちょっと末尾に余分なスペースを入れてみよう。
1
2
> parseTest expr $ pack "1+2*3 "
Done " " Add (Nat 1) (Mul (Nat 2) (Nat 3))
どうやら、直前までは、うまく解析できてるみたい。。よかったー(?)。 今日は、この辺で勘弁してください。attoparsec を深く理解するには、ByteString,Text あたりの知識が必要かも(ByteString, Text については、私もまだ勉強していません)

(5): さらに勉強するための情報源

なんとか、Parsec3 と attoparsec を使って、動作するコードを実装し、雰囲気を掴みました。あとは、情報があれば、自分で勉強していけそうです。勉強会, Twitter で、参考になる情報源を紹介していただいたので、ここにまとめてみます。
Parsec3 や、attoparsec の使い方について、もう少し詳しい解説記事があると、喜ぶ人が多そうです(私も含めて)。私も上記の文書は、まだ勉強できていませんが、理解が進んだらまた紹介したいと思います。

2011年11月30日水曜日

お絵描き群ロボット

ちょっと前になりますが、 GetRobo さんが、GetRobo Forum というイベントを開催され、参加してきました〜。いろんな人と楽しく話しているうちに、ほとんど飲食する暇もなく終了。ロボット関連の方々と交流できた貴重な機会でした。

そのとき、昔わたしが作った 「お絵描き群ロボット」を紹介したら、結構興味を持ってもらえたので、紹介します。

「お絵描き群ロボット」は、会社のアイディアコンテストの作品として制作したもので、「iPad に指で曲線を入力すると、その形状に沿って群ロボットが整列する」というものです。こんな感じ↓


制作するのに、どえらい苦労をしたというのにも興味を持ってくれた人がいたので、紹介します。

夢卵2010 お絵描き群ロボット 制作編
View more presentations from utotch

ロボットに興味を持っている人の集まりだったので、結構ウケてくれてうれしかったです。