【Haskell】 インデントで表現された木構造のパース
今日はhaskellネタ。
現在私が務めている会社は、良くも悪くも日本の伝統的な製造業といった感じなので、 今のところ、haskellを製品のソフトウェア開発に使う機会は全くないのですが1、 excelデータ(csvとかtsv)の処理等で、haskellをスクリプト的にを使っています。
今回も普通のサラリーマンの日常業務をhaskellで効率化するのを念頭に、 記事を書いてみます。
普通のサラリーマンが出会うデータは大抵の場合excelデータだと思うので、 以下の様なモデルを考えています。
入力: xlsデータ
出力: xlsデータ
手順
また、日常的に(excelで)扱うデータ形式は、大抵の場合、
の2種類だと思うので、今回は、 インデントで表現された木構造のパース方法について、書いていこうと思います2。
インデントて表現された木構造のパース
indentsパッケージ利用します。
前置きが長くなりましたが、以下がソースコードです。
module IndentedTree where
import Control.Applicative ( (*>) )
import Data.Char (isSpace)
import Data.Tree (Tree (..))
import Text.Parsec (many1, letter, try, option, spaces, char, runParserT)
import Text.Parsec.Indent (withBlock, runIndent, IndentParser(..))
import MyParser (float) -- 浮動小数点をパースする適当なパーサー
type Parser a = IndentParser String () a
parseIndentedTree input = runIndent "" $ runParserT aTree () "" input
aTree :: Parser (Tree (String, Double))
aTree = spaces *> withBlock Node aNodeHeader aTree
aNodeHeader :: Parser (String, Double)
aNodeHeader = do
str <- many1 letter
i <- option 0 (char ':' *> float)
spaces
return (str, i)
-- 入力例
example = unlines [
"foo:100",
" knf:2",
" inf:5",
" enx:15",
" indent",
" dog:4",
" bar:10",
" kobolt",
" wkoiking:6",
" taiwan",
" copilot:50"
実行結果
特に、説明をしなくても、Text.Parsec.Indentモジュールの使い方は明瞭だと思いますが、 一点だけ注意点があります:
withBlock
コンビネータは現在のインデントの深さで、入れ子構造を判断しますが、 それ自身は入力列のスペースを消費しません。したがって、スペースを明示的に読み飛ばすのを 忘れないようにしなければなりません。
参考にしたサイト
おまけ
Pandocで脱Word
職場でWordを使って文章を書いていると、どうもSAN値が低下するので、 markdownで高品質な文章が書ける環境を模索しました。
その結果、Pandoc + xyzzyで快適に文章が書けるようになった1ので、 紹介したいと思います。
ちなみに、環境はWindows XP or Windows 7です。
Pandocとは
haskellという言語で書かれたドキュメント・コンバータです。
かなり多様なファイル形式に対応していますが、基本的に
- markdown → html
- markdown → (latex) → pdf
- markdown → docx
といった感じでmarkdownでhtml文章や紙媒体の文章を書くためのツールだと思っています。
pandoc markdown
Pandocはpandoc markdownという独自のmarkdown記法を定義しています。
何ができるのか
- 見出しとか、
- 箇条書きとか、
- 表とか、
- 図とか、
- 数式とか、
- コードとか、
- 目次の自動生成とか、
- 図表番号参照とか、
要するに文章書くのに必要なことはだいたいできます。
ちなみに、このブログの記事はPandoc Markdownで書かれています:
サンプル用に書いたhtml文章と紙媒体の文章です:
参考サイト
導入にいたっては、以下のサイトを参考にしました。
- Pandocのインストール
-
日本語の環境構築
htmlはテキスト・エディタのエンコーディングをutf-8にすればOKです。
まずないと思いますが、需要があれば、環境構築など、記事を 書こうと思います。
-
まだ、docxを使わざるを得ない時も多々ありますが。?
KaMailV3で業務効率を改善
学生の頃からかれこれ5年以上、xyzzy を使い続けているのですが、 特に最近、KaMailV3 で色々捗っているので、 KaMailV3導入時に参考にしたサイトをまとめておきます。
ちなみに、私がKaMailV3導入に成功した環境は以下の3つです。
- 普通のPOP3、SMTP
- Microsoft Exchange Server
- Gmail
KaMailV3の導入
作者の服部さんサイト の「インストール」及び「設定」に従います。
注意点
Exchange Server
フリーソフトDavMail Gatewayを使用して、Outlook Web Access経由でメールを送受信します。
Gmail
POPFile経由でGMailをKaMailV3で読むを参照。
KamailV3関連拡張lisp
以下の拡張lispをインストールするとさらに幸せになると思います。
初めての記事
はじめてのの記事(テスト)
ここに本文1がきます。
ヘッダー2
ここが本文2です。
以下、コードの挿入です。
module FFT where
import Control.Arrow ( (***) )
import Data.Complex (Complex, cis)
import Data.List (partition)
type Signal = [Complex Double]
-- 信号処理の基礎的な演算
fft, ifft :: Signal -> Signal
fft = fft' 1
ifft = fft' (-1)
fft' m ls = fft'' m (fromIntegral $ length ls) ls
fft'' :: Double -> Double -> Signal -> Signal
fft'' m 1 ls = ls
fft'' m n ls
= zipWith3 (\e c o -> (e + c * o) / sqrt 2) (es ++ es) cs (os ++ os)
where
(es,os) = dup (fft'' m n') $ ipartition (\k _ -> even k) ls
cs = [cis (m * 2 * pi * k / n) | k <- [0..(n-1)]]
n' = scaleFloat (-1) n
ipartition :: (Int -> a -> Bool) -> [a] -> ([a], [a])
ipartition f = dup (map snd) . partition (uncurry f) . zip [0..]
dup f = f *** f
(<**>) :: Signal -> Signal -> Signal
x <**> y = map (/ n) $ ifft $ zipWith (*) (fft x) (fft y)
where
n = fromIntegral $ length x
箇条書きのテストです。
画像の挿入。
Right | Left | Center | Default |
---|---|---|---|
12 | 12 | 12 | 12 |
123 | 123 | 123 | 123 |
1 | 1 | 1 | 1 |
数式
引用
これは、引用された文章です。