SlideShare a Scribd company logo
1 of 37
Download to read offline
One
Common Lispでもワンライナーしたい
自己紹介
● twitter: @sin_clav
● github: @t-sin
● 野生のCommon Lisp使い
● おしごとはnil
今日お話しすること
● Common Lispでワンライナー
やったらツラかった(動機)
● ワンライナーを楽にしてやるぜ(結果)
● どうワンライナーするのか(使い方)
● その内部構造(設計・実装)
シェルのワンライナー
よくお世話になりますよね
よくやるワンライナー(1)
● アクセスログ中のhoge APIへのアクセス
● そのログ中のhoge APIのアクセス数
$ cat /var/log/nginx/access.log | grep /api/hoge
xx.xx.xx.xx - - [21/Oct/…] "GET / HTTP/1.1" ….
xx.xx.xx.xx - - [22/Oct/…] "GET / HTTP/1.1" ….
xx.xx.xx.xx - - [24/Oct/…] "GET / HTTP/1.1" ….
$ cat /var/log/nginx/access.log | grep /api/hoge |
wc -l
● 3
よくやるワンライナー(2)
● CSVファイル中の2列目の合計
$ cat data.csv
id1,1
id2,2
id3,3
$ cat data.csv | awk -F , '{sum+=$2}END{print sum}'
6
よくやるワンライナー(2)
● CSVファイル中の2列目の合計
shell以外の言語(awk)おぼえないとダメ…?
$ cat data.csv
id1,1
id2,2
id3,3
$ cat data.csv | awk -F , '{sum+=$2}END{print sum}'
6
Common Lispでやってみる
● CSVファイル中の2列目の合計
● ぜんぶCommon Lispで。
$ cut -d ',' -f 2 data.csv | ros run -e '(print
(loop for line = (read *standard-input* nil :eof)
until (eq :eof line) sum line))' -q
6
$ ros -s split-sequence -e '(with-open-file (in
"data.csv") (print (loop for l = (read-line in
nil :eof) until (eq l :eof) sum (parse-integer (nth
1 (split-sequence:split-sequence #, l))))))' -q
● 6
ながすぎてしぬ
われわれはどうすればいいのだ……
ワンライナーっぽさのために
● 入力まわりのタイプ数を減らす
– *standard-input*
– with-open-fileうんぬん
– 行に対してのloop
● 「処理」の合成っぽく書けるとよい
ワンライナーを支援するワン!
● CSVの2列目合計をoneで。
● ぜんぶoneで。
$ cut -d ',' -f 2 data.csv | ros one '(one:for* - <
one:read* +> + 0)'
6
$ ros one '(one:for* #P"data.csv" < one:read-line*
$ #/(split-sequence #, _) $ #/(nth 1 _) $ parse-
integer +> + 0)'
6
Oneとは
「処理」を
連結して
入力をwrapする
ライブラリです!!
Oneの機能概要
ゆるいお気持ちでお聞ききください
Oneの基本構文
● 前段の入力を、次の記号で受ける
CL-USER> (one:for 入力 [記号 パラメータ]*)
Oneの基本構文
● 前段の入力を、次の記号で受ける
CL-USER> (one:for 入力 [記号 パラメータ]*)
オブジェクト,
stream,
pathname
パイプ的な記号
$, ?, <, >, +>
1引数関数,
シンボル
Oneの基本構文
● 前段の入力を、次の記号で受ける
● 1引数lmbda式用リーダマクロ
CL-USER> (one:for 入力 [記号 パラメータ]*)
オブジェクト,
stream,
pathname
パイプ的な記号
$, ?, <, >, +>
1引数関数,
シンボル
;; (lambda (input) (search "hoge" input)) と同じ
#/(search "hoge" _)
入力
記号`$`: 処理の合成
● 前段の入力にパラメータ(処理)を合成
● 例
CL-USER> (one:for 入力 $ 関数or関数名 ...)
CL-USER> (one:for 1 $ print)
"1" ; 入力にprintが適用された
CL-USER> (one:for 1 $ 1+ $ print)
"2" ; 1+の後にprintが適用された
記号`<`: 入力の上を繰り返し
● 前段の入力の上をloopする(関数で)
● 例
CL-USER> (one:for 入力 < 関数or関数名 ...)
CL-USER> (one:for '(1 2 3) < cdr $ princ)
123 ; cdrでloopしたものが出力された
CL-USER> (one:for #P"nums.csv" < one:read-line* $
print)
"id1,1"
"id2,2" ; read-line* (:EOFで終わる) でloopした
記号`?`: 条件によるフィルタ
● 前段の入力のうち述語でtになるもののみ通す
● 例
CL-USER> (one:for 入力 ? 述語 ...)
● CL-USER> (one:for '(1 2 3) < cdr ? oddp $ print)
1
3 ; 奇数だけが出力された
記号`>`: 処理結果を溜め込む
● 前段の入力をリストに溜め込んで処理する
● 例
CL-USER> (one:for 入力 > 変換する関数 ...)
CL-USER> (one:for 1 > identity $ print)
(1) ; 入力がリストになる
CL-USER> (one:for '(1 2 3) < cdr > identity $
print)
(1 2 3) ; 前段の入力すべてがリストになる
CL-USER> (one:for '(1 2 3) < cdr > #/(apply #'+ _)
$ print)
6 ; 合計された
記号`+>`: 処理結果を畳み込む
● 前段の入力をバッファせずに畳み込む
● 例
CL-USER> (one:for 入力 +> 2引数関数 [初期値] ...)
CL-USER> (one:for '(1 2 3) < cdr +> (lambda (a b)
(+ a b)) 0 $ print)
6 ; 足し込まれた
; 長い。lambdaの部分が+だけで書けるといいかも
実際の使用例
ここからが本当にやりたかったことです
ワンライナーを支援するワン!
● CSVの2列目合計
● 標準入力をソート
$ seq 1 5 | shuf | ros one "(one:for* - < one:read-
line* > #/(sort _ #'string<))"
1
…
5
$ ros one '(one:for* #P"data.csv" < one:read-line*
$ #/(split-sequence #, _) $ #/(nth 1 _) $ parse-
integer +> + 0)'
6
シェル芸(1): 響け!ユーフォニアム
『【ファン迷惑】「響け!ユーフォニアム」という文字列だけで遊
ぶシェル芸人達』, https://togetter.com/li/1041621
$ echo 響け!ユーフォニアム | ros one '(one:for - <
one:read-line* $ #/(cons _ (length _)) $ #/(cons
(repeat-sequence (car _) (1+ (cdr _))) (cdr _)) $ #/
(batches (car _) (1+ (cdr _))) < cdr $ #/(format t "~a~
%" _))'
響け!ユーフォニアム響
け!ユーフォニアム響け
!ユーフォニアム響け!
ユーフォニアム響け!ユ
ーフォニアム響け!ユー
フォニアム響け!ユーフ
ォニアム響け!ユーフォ
ニアム響け!ユーフォニ
アム響け!ユーフォニア
ム響け!ユーフォニアム
シェル芸(2): サンシャイン池崎ゲーム
https://twitter.com/ziuziu/status/918070729341587457
$ echo いまはもううごかないおじいさんのとけい | ros one
'(one:for* - < one:read-line* $ #/(ppcre:regex-replace-
all "い" _ "イェー!"))'
イェー!まはもううごかなイェー!おじイェー!さんのとけ
イェー!
Oneの中身は?
(ちなみにここまででスライド26枚です)
設計のポイント
● 部品となる「処理」を独立させる
● 処理間を渡るデータはLispオブジェクト
● 省タイプ化
– 入力に対する制御構文(loopやif)を隠す
– 入力の煩雑な処理(長い名前等)を隠す
● 省メモリ
パイプを見直す
$ cat access.log | grep html | sed 日時 | sort
パイプを見直す
$ cat access.log | grep html | sed 日時 | sort
grep sedcat sort
パイプを見直す
$ cat access.log | grep html | sed 日時 | sort
grep sedcat sort
grep sedcat sort( )) ) )(((
パイプを見直す
$ cat access.log | grep html | sed 日時 | sort
grep sedcat sort
grep sedcat sort( )) ) )(((
(sort (sed (grep (cat "access.log"))))
パイプを見直す
$ cat access.log | grep html | sed 日時 | sort
grep sedcat sort
grep sedcat sort( )) ) )(((
(sort (sed (grep (cat "access.log"))))
関数合成だ!
〜パイプからLispへ〜
省メモリを考える
● 入力を全部メモリに置いてはダメ
● 入力はすぐ次の処理に流す
;; ダメなコード
;; (access.logが10GBあったら…?)
(sort (mapcar #'sed
(mapcar #'grep
(cat "access.log")))
#'string<)
(sort (loop
:for line in (cat "access.log")
:when (grep line)
:collect (sed line))
#'string<)
処理フローの組み立て(1)
● 内部でこんなコールグラフをもつ、いっこの
lambda式をつくりたい
cat
grep
grep
grep
grep
sed
sed
sed
sort
< ? >
: 入力の流れ
: 処理のlambda式
処理フローの組み立て(2)
● lambda式を連ねてフローを作る
– こんな関数でパーツを…
– 連ねる
;;`$`はだいたいこんな感じ
(defun compose (fn2 fn1)
(lambda (input)
(funcall fn2 (funcall fn1 input)))
;; cat | grep | sed
(compose (compose #'grep #'sed) #'cat)
感想
● lambda式の入れ子地獄はデバッグつらい
● シェルやREPLで、まあまあ使える
● まだまだ改善の余地ありそう
– `+>`に2引数lambda式を書くところなど
Oneをためしに使ってみてね。
`$ ros install t-sin/one`で入るよ!

More Related Content

What's hot

Python 3.6 リリースパーティー 発表資料
Python 3.6 リリースパーティー 発表資料Python 3.6 リリースパーティー 発表資料
Python 3.6 リリースパーティー 発表資料Atsuo Ishimoto
 
ひのきのぼうだけで全クリ目指す
ひのきのぼうだけで全クリ目指すひのきのぼうだけで全クリ目指す
ひのきのぼうだけで全クリ目指すAromaBlack
 
すごい constexpr たのしくレイトレ!
すごい constexpr たのしくレイトレ!すごい constexpr たのしくレイトレ!
すごい constexpr たのしくレイトレ!Genya Murakami
 
Constexpr 中3女子テクニック
Constexpr 中3女子テクニックConstexpr 中3女子テクニック
Constexpr 中3女子テクニックGenya Murakami
 
Python 機械学習プログラミング データ分析ライブラリー解説編
Python 機械学習プログラミング データ分析ライブラリー解説編Python 機械学習プログラミング データ分析ライブラリー解説編
Python 機械学習プログラミング データ分析ライブラリー解説編Etsuji Nakai
 
SECDマシン 実装と動きとその他もろもろについて
SECDマシン 実装と動きとその他もろもろについてSECDマシン 実装と動きとその他もろもろについて
SECDマシン 実装と動きとその他もろもろについてt-sin
 
constexpr関数はコンパイル時処理。これはいい。実行時が霞んで見える。cpuの嬌声が聞こえてきそうだ
constexpr関数はコンパイル時処理。これはいい。実行時が霞んで見える。cpuの嬌声が聞こえてきそうだconstexpr関数はコンパイル時処理。これはいい。実行時が霞んで見える。cpuの嬌声が聞こえてきそうだ
constexpr関数はコンパイル時処理。これはいい。実行時が霞んで見える。cpuの嬌声が聞こえてきそうだGenya Murakami
 
Write good parser in perl
Write good parser in perlWrite good parser in perl
Write good parser in perlJiro Nishiguchi
 
Scapy presentation Remake(訂正)
Scapy presentation Remake(訂正)Scapy presentation Remake(訂正)
Scapy presentation Remake(訂正)ashigirl ZareGoto
 
GNU awk (gawk) を用いた Apache ログ解析方法
GNU awk (gawk) を用いた Apache ログ解析方法GNU awk (gawk) を用いた Apache ログ解析方法
GNU awk (gawk) を用いた Apache ログ解析方法博文 斉藤
 
Node.js - sleep sort algorithm
Node.js - sleep sort algorithmNode.js - sleep sort algorithm
Node.js - sleep sort algorithmtakesako
 
メタメタプログラミングRuby
メタメタプログラミングRubyメタメタプログラミングRuby
メタメタプログラミングRubyemasaka
 

What's hot (20)

Python 3.6 リリースパーティー 発表資料
Python 3.6 リリースパーティー 発表資料Python 3.6 リリースパーティー 発表資料
Python 3.6 リリースパーティー 発表資料
 
ひのきのぼうだけで全クリ目指す
ひのきのぼうだけで全クリ目指すひのきのぼうだけで全クリ目指す
ひのきのぼうだけで全クリ目指す
 
Boost tour 1.60.0 merge
Boost tour 1.60.0 mergeBoost tour 1.60.0 merge
Boost tour 1.60.0 merge
 
pecoを使おう
pecoを使おうpecoを使おう
pecoを使おう
 
すごい constexpr たのしくレイトレ!
すごい constexpr たのしくレイトレ!すごい constexpr たのしくレイトレ!
すごい constexpr たのしくレイトレ!
 
Boost Tour 1.48.0 diff
Boost Tour 1.48.0 diffBoost Tour 1.48.0 diff
Boost Tour 1.48.0 diff
 
Constexpr 中3女子テクニック
Constexpr 中3女子テクニックConstexpr 中3女子テクニック
Constexpr 中3女子テクニック
 
Python 機械学習プログラミング データ分析ライブラリー解説編
Python 機械学習プログラミング データ分析ライブラリー解説編Python 機械学習プログラミング データ分析ライブラリー解説編
Python 機械学習プログラミング データ分析ライブラリー解説編
 
SECDマシン 実装と動きとその他もろもろについて
SECDマシン 実装と動きとその他もろもろについてSECDマシン 実装と動きとその他もろもろについて
SECDマシン 実装と動きとその他もろもろについて
 
constexpr関数はコンパイル時処理。これはいい。実行時が霞んで見える。cpuの嬌声が聞こえてきそうだ
constexpr関数はコンパイル時処理。これはいい。実行時が霞んで見える。cpuの嬌声が聞こえてきそうだconstexpr関数はコンパイル時処理。これはいい。実行時が霞んで見える。cpuの嬌声が聞こえてきそうだ
constexpr関数はコンパイル時処理。これはいい。実行時が霞んで見える。cpuの嬌声が聞こえてきそうだ
 
Write good parser in perl
Write good parser in perlWrite good parser in perl
Write good parser in perl
 
Scapy presentation Remake(訂正)
Scapy presentation Remake(訂正)Scapy presentation Remake(訂正)
Scapy presentation Remake(訂正)
 
R3.0.0 is relased
R3.0.0 is relasedR3.0.0 is relased
R3.0.0 is relased
 
Rでreproducible research
Rでreproducible researchRでreproducible research
Rでreproducible research
 
Scapy presentation
Scapy presentationScapy presentation
Scapy presentation
 
Glibc malloc internal
Glibc malloc internalGlibc malloc internal
Glibc malloc internal
 
Find(1)
Find(1)Find(1)
Find(1)
 
GNU awk (gawk) を用いた Apache ログ解析方法
GNU awk (gawk) を用いた Apache ログ解析方法GNU awk (gawk) を用いた Apache ログ解析方法
GNU awk (gawk) を用いた Apache ログ解析方法
 
Node.js - sleep sort algorithm
Node.js - sleep sort algorithmNode.js - sleep sort algorithm
Node.js - sleep sort algorithm
 
メタメタプログラミングRuby
メタメタプログラミングRubyメタメタプログラミングRuby
メタメタプログラミングRuby
 

Similar to One - Common Lispでもワンライナーしたい

Boost jp9 program_options
Boost jp9 program_optionsBoost jp9 program_options
Boost jp9 program_optionsnyaocat
 
これからの「言語」の話をしよう ―― 未来を生きるためのツール
これからの「言語」の話をしよう ―― 未来を生きるためのツールこれからの「言語」の話をしよう ―― 未来を生きるためのツール
これからの「言語」の話をしよう ―― 未来を生きるためのツールNobuhisa Koizumi
 
C++コミュニティーの中心でC++をDISる
C++コミュニティーの中心でC++をDISるC++コミュニティーの中心でC++をDISる
C++コミュニティーの中心でC++をDISるHideyuki Tanaka
 
Common LispでGPGPU
Common LispでGPGPUCommon LispでGPGPU
Common LispでGPGPUgos-k
 
ZFSのソースコードをチラ見してみる
ZFSのソースコードをチラ見してみるZFSのソースコードをチラ見してみる
ZFSのソースコードをチラ見してみるKoichi Suzuki
 
2017-12-04 Linuxの基本構造とBashでの扱い方
2017-12-04 Linuxの基本構造とBashでの扱い方2017-12-04 Linuxの基本構造とBashでの扱い方
2017-12-04 Linuxの基本構造とBashでの扱い方浩平 渡邉
 
Cli mini Hack!#1 ~Terminalとの親睦を深めよう~
Cli mini Hack!#1 ~Terminalとの親睦を深めよう~Cli mini Hack!#1 ~Terminalとの親睦を深めよう~
Cli mini Hack!#1 ~Terminalとの親睦を深めよう~Kei IWASAKI
 
つくっておぼえる!仮想マシン〜直前で実装編〜
つくっておぼえる!仮想マシン〜直前で実装編〜つくっておぼえる!仮想マシン〜直前で実装編〜
つくっておぼえる!仮想マシン〜直前で実装編〜Eric Sartre
 
シェル芸初心者によるシェル芸入門
シェル芸初心者によるシェル芸入門シェル芸初心者によるシェル芸入門
シェル芸初心者によるシェル芸入門icchy
 
OCamlのアセンブラを読む話
OCamlのアセンブラを読む話OCamlのアセンブラを読む話
OCamlのアセンブラを読む話nomaddo
 
10min r study_tokyor25
10min r study_tokyor2510min r study_tokyor25
10min r study_tokyor25Nobuaki Oshiro
 
10min r study_tokyor25
10min r study_tokyor2510min r study_tokyor25
10min r study_tokyor25Nobuaki Oshiro
 
Java SE 8 lambdaで変わる プログラミングスタイル
Java SE 8 lambdaで変わる プログラミングスタイルJava SE 8 lambdaで変わる プログラミングスタイル
Java SE 8 lambdaで変わる プログラミングスタイルなおき きしだ
 
そんな装備で大丈夫か?
そんな装備で大丈夫か?そんな装備で大丈夫か?
そんな装備で大丈夫か?2celeb
 
Application Developer Festival 2015 LT
Application Developer Festival 2015 LTApplication Developer Festival 2015 LT
Application Developer Festival 2015 LTJunpei Matsuda
 
Lisp Tutorial for Pythonista : Day 3
Lisp Tutorial for Pythonista : Day 3Lisp Tutorial for Pythonista : Day 3
Lisp Tutorial for Pythonista : Day 3Ransui Iso
 

Similar to One - Common Lispでもワンライナーしたい (20)

Boost jp9 program_options
Boost jp9 program_optionsBoost jp9 program_options
Boost jp9 program_options
 
Ilstudy001_20110806
Ilstudy001_20110806Ilstudy001_20110806
Ilstudy001_20110806
 
Unix
UnixUnix
Unix
 
これからの「言語」の話をしよう ―― 未来を生きるためのツール
これからの「言語」の話をしよう ―― 未来を生きるためのツールこれからの「言語」の話をしよう ―― 未来を生きるためのツール
これからの「言語」の話をしよう ―― 未来を生きるためのツール
 
C++コミュニティーの中心でC++をDISる
C++コミュニティーの中心でC++をDISるC++コミュニティーの中心でC++をDISる
C++コミュニティーの中心でC++をDISる
 
Common LispでGPGPU
Common LispでGPGPUCommon LispでGPGPU
Common LispでGPGPU
 
ZFSのソースコードをチラ見してみる
ZFSのソースコードをチラ見してみるZFSのソースコードをチラ見してみる
ZFSのソースコードをチラ見してみる
 
Tokyor23 doradora09
Tokyor23 doradora09Tokyor23 doradora09
Tokyor23 doradora09
 
0x300
0x3000x300
0x300
 
2017-12-04 Linuxの基本構造とBashでの扱い方
2017-12-04 Linuxの基本構造とBashでの扱い方2017-12-04 Linuxの基本構造とBashでの扱い方
2017-12-04 Linuxの基本構造とBashでの扱い方
 
Cli mini Hack!#1 ~Terminalとの親睦を深めよう~
Cli mini Hack!#1 ~Terminalとの親睦を深めよう~Cli mini Hack!#1 ~Terminalとの親睦を深めよう~
Cli mini Hack!#1 ~Terminalとの親睦を深めよう~
 
つくっておぼえる!仮想マシン〜直前で実装編〜
つくっておぼえる!仮想マシン〜直前で実装編〜つくっておぼえる!仮想マシン〜直前で実装編〜
つくっておぼえる!仮想マシン〜直前で実装編〜
 
シェル芸初心者によるシェル芸入門
シェル芸初心者によるシェル芸入門シェル芸初心者によるシェル芸入門
シェル芸初心者によるシェル芸入門
 
OCamlのアセンブラを読む話
OCamlのアセンブラを読む話OCamlのアセンブラを読む話
OCamlのアセンブラを読む話
 
10min r study_tokyor25
10min r study_tokyor2510min r study_tokyor25
10min r study_tokyor25
 
10min r study_tokyor25
10min r study_tokyor2510min r study_tokyor25
10min r study_tokyor25
 
Java SE 8 lambdaで変わる プログラミングスタイル
Java SE 8 lambdaで変わる プログラミングスタイルJava SE 8 lambdaで変わる プログラミングスタイル
Java SE 8 lambdaで変わる プログラミングスタイル
 
そんな装備で大丈夫か?
そんな装備で大丈夫か?そんな装備で大丈夫か?
そんな装備で大丈夫か?
 
Application Developer Festival 2015 LT
Application Developer Festival 2015 LTApplication Developer Festival 2015 LT
Application Developer Festival 2015 LT
 
Lisp Tutorial for Pythonista : Day 3
Lisp Tutorial for Pythonista : Day 3Lisp Tutorial for Pythonista : Day 3
Lisp Tutorial for Pythonista : Day 3
 

One - Common Lispでもワンライナーしたい