Common Lispにおいてワンライナーやシェル芸をすることは至難です。そこでワンライナーを支援するライブラリ one (https://github.com/t-sin/one) をつくりました。
このスライドは、oneについてlisp meetup で発表したときのものです。
8. リスト内包表記で順次処理
or や and の短絡評価を利用する
# printの返り値はNone
>>> [print("hello") or print("bye") for n in [None]]
hello
bye
[None]
値がある関数の場合は…
>>> [(str(42) and None) or print('hi') for n in [None]]
hi
[None]
9. リスト内包表記で代入
リストのリストを操作する場合、 n によって空リストを参照可能
>>> [lis.append(n) or lis for n in range(3)
... for lis in [[]]]
[[0], [1], [2]]
ちなみにこのforを逆にすると、こうなる
>>> [lis.append(n) or lis for lis in [[]]
... for n in range(3)]
[[0, 1, 2], [0, 1, 2], [0, 1, 2]]
内側の for が外側のループのローカル変数になるっぽい
lambda 式を代入(名前付け)することで、再帰できます
10. リスト内包表記で条件分岐
いくつか方法がある:
>>> [print(n) for n in range(3) if n % 2 == 0]
0
2
[None, None]
>>> [print(n) if n % 2 == 0 else 'w' for n in range(3)]
0
2
[None, 'w', None]
後者のほうが、複数の if を連ねて switch するのに便利
14. LISC
LISP = LISt Proccessing
LISC = LISt Comprehension
https://github.com/t-sin/lisc/blob/master/lisc.py
15. LISC (コード)
[[b.append(l_read(_make_stream(input('> ')))) or
(print(l_print(l_eval(b[-1], _env))) if b[-1] is not None else
b.append('')) for b in [[None]] for a in b] for _read_char in
[lambda stream: [(stream.pop() and None) or
stream.append(-1) or (None, stream) if pos >= len(stream[0])
else (None, stream) if pos == -1 else c.append(stream[0][pos])
or (stream.pop() and None) or stream.append(pos+1) or (c[0],
stream) for c in [[]] for pos in [stream[1]]][0]] for _peek_char in
[lambda stream: [(None, stream) if pos >= len(stream[0]) else
(None, stream) if pos == -1 else (stream[0][pos], stream) for
pos in [stream[1]]][0]] for _make_stream in [lambda s: [s, 0]]
for _read_list in [lambda stream: [[(_read_char(stream) and
None) or loop[1:] if _peek_char(stream)[0] == ')' else loop[1:] if
_peek_char(stream)[0] == None else loop.a ...
以下省略
20. つらかったこと
リーダの実装とリスト内包表記化を同時にやったらハマった
文字列 -> (結果, 読んだ文字数) の形にしようとした
ストリーム(パーサ状態を分離)にしたら簡単になった
デバッグがめっちゃつらい
そういえば難読化系の手法だった
エラー表示も役に立たない
>>> [[b.append(l_read(_make_stream(input('> ')))) or
(print(l_print(l_eval(b[-1], _env))) if b[-1] is not None
else b.append('')) for b in [[None]] for a in b] for _read_cha
in [lambda stream: [(stream.pop() and None) or stream.append(
...
^ # これはどこを指しているんだ