One-liner in Haskell
Haskellを現場言語にするために、こんなものを作ってみました。
hoe: Haskell One-liner Evaluator
(名前には深い意味はありません。)
Haskellでワンライナーをやろうという誰得なツールです。誰得ですが、ワンライナーでも、型があると便利なんではなかろうか、型を元にユーザの望みの動作が大体決定できるんではなかろうか、という発想を元に作られました。
Haskellのワンライナーは、ghc -e でも評価できますが、これは (Show a) => a か、 (Show a) => IO a な型しか評価できません。hoeでは、String -> String など、もっと色々な型を評価できます。そして、その型に応じていい感じの動作が自動的に選択されます。
例えば、idを入力すると、入力がそのまま出力されます。
$ cat tmp Hello, Haskell World! $ hoe 'id' tmp Hello, Haskell World!
そうです。もうcatを作るのに、
http://d.hatena.ne.jp/nobsun/20100820/1282270092
こんなプログラムを書く必要は無いんです。
文字処理
Char -> Char なら、文字列全体に与えられた関数を適用します。
$ cat tmp | hoe 'toUpper' HELLO, HASKELL WORLD!
大変単純明快です。
[a] -> [a] ほか
基本的にhoeは、行指向の振る舞いをします。
[a] -> [a] は、[String] -> [String] にも String -> String にもマッチしますが、このような場合は [String] -> [String] が選択されます。例えば、take 2 なら、先頭から2行を取ってくる処理になります。
$ cat tmp Hello, Haskell World! $ cat tmp | hoe 'take 2' $ hoe 'take 2' tmp Hello, Haskell
また、sort なら、行をソートする処理になります。
$ cat tmp | hoe 'sort' Haskell Hello, World!
大変シンプル。
String -> String の関数を書いた場合も、行ごとの処理になります。
$ cat tmp | hoe '("> "++)' > Hello, > Haskell > World!
行番号
Int -> String -> String などの関数を書けば、第一引数に行番号が入ります。
$ cat tmp | hoe '\ln s -> show ln ++ "> " ++ s' 1> Hello, 2> Haskell 3> World!
先頭に行番号を書いたりするのも、このとおり。
(Int, String) を返せば、第一引数でソートした結果が出力になります。
$ cat tmp | hoe '\_ s -> (length s, s)' Hello, World! Haskell
これは、行を長さでソートします。
関数のlift/join
行ごとではなく、文字ごとに処理したい場合もあります。
たとえば、drop 2 と書くと、先頭2行を落とす処理になりますが、各行2文字落とす処理が書きたいとしましょう。これは
$ cat tmp | hoe 'map $ drop 2' llo, skell rld!
のように、mapを用いればできますが、これはめんどくさい。そこで、与えられた関数を [String] -> [String] ではなく、 String -> String と解釈する --join (-j) オプションを用意しました(現在の実装は極めていい加減なので、型によってはうまく動かない時もあるかもしれませんし、joinじゃなくてliftするかもしれません)。これを用いると、
$ cat tmp | hoe -j 'drop 2' llo, skell rld!
と書けます。
モジュール自動import
hoeは、独断と偏見で選別したよく使われるライブラリを、自動的にimportしています。上での例でのtoUpperが装飾なしで使えていたのはこのおかげです。
なので、例えば行の長さでのソートは
$ cat tmp | hoe 'sortBy $ comparing length' Hello, World! Haskell
このようにも書けます。
inplaceモード
- i を付けると、与えたファイルを書き換えます。
例えば、
$ hoe -i 'toUpper' *
とやると、すべてのファイルを大文字にします。-iオプションに文字列を渡すと、
$ hoe -i.bak 'toUpper' *
元のファイルに.bakを付けたファイル名でバックアップが作成されます。安心です。
値評価モード
当然ですが ghc -e でできる単なる (Show a) => a や、(Show a) => IO a の評価もできます。
$ hoe '2^100' 1267650600228229401496703205376
$ hoe 'pi*50^2' 7853.981633974483
電卓としても使えますね。
$ hoe 'forM [1..10] $ \i -> writeFile ("tmp."++show i) ""'
ゴミファイルの生成もお手の物。
あとがき
という訳で、誰得ツールを作ったお話でした。
超適当な実装で、まだまだ全然機能がありませんが、
ご意見ご感想などあればどしどしご送信下さい。