Seriesで響け!ユーフォニアム!
Series触る触ると言ってたのに触ってなかったので、手始めに響けユーフォニアムをseriesでやってみました。
2017/4/29 追記
「妙なwarningが出てしまうこと」について、以下の記事の反応をいただきました。
この記事ではapply
でseriesをつくっているために、seriesの最適化のしくみにこの記事のコードを載せることができなかったのが原因なのでしょう。
Seriesとは
Seriesは、Common Lispに導入されかけたけど時間がないので却下されたという、繰り返し構造を宣言的に表現するためのしくみです。Seriesを使えばHaskellやClojureのような、関数型言語っぽいデータ処理ができそうな感じです。
仕様は"Common Lisp the Language 2nd Edition"の付録Aに書かれています。英語ならウェブでも読めます。
また日本語の説明は次のページが詳しいです。
ちなみに使うときはこんな感じです。
CL-USER> (ql:quickload :series) CL-USER> (use-package :series) CL-USER> (collect 'string (subseries (apply #'series (coerce "グソクムシ" 'list)) 0 20)) "グソクムシグソクムシグソクムシグソクムシ"
響け!ユーフォニアムとは
アニメの名前で、ぼくは見ていませんが、ちょっと前にtwitterでこんな遊びがはやっていました。
その時期にぼくもCommon Lispのformat
関数でやってみたりしたので、とりあえずseriesの入門としてやってみるのにいいのではと思った次第です。
redditのlisp_jaが、似た問題でちょっと盛り上がってた時期がありました。
結果…
Seriesのままならこんなかんじ:
CL-USER> (let* ((str "響け!ユーフォニアム") (len (length str))) (mapping ((i (scan-range :from 0 :by 1 :upto len))) (collect 'string (subseries (apply #'series (coerce str 'list)) i (+ i len))))) #Z("響け!ユーフォニアム" "け!ユーフォニアム響" "!ユーフォニアム響け" "ユーフォニアム響け!" "ーフォニアム響け!ユ" "フォニアム響け!ユー" "ォニアム響け!ユーフ" "ニアム響け!ユーフォ" "アム響け!ユーフォニ" "ム響け!ユーフォニア" "響け!ユーフォニアム")
問題に沿って標準出力に出力するならこうか:
CL-USER> (let* ((str "響け!ユーフォニアム") (len (length str))) (iterate ((i (scan-range :from 0 :by 1 :upto len))) (format t "~a~%" (collect 'string (subseries (apply #'series (coerce str 'list)) i (+ i len)))))) 響け!ユーフォニアム け!ユーフォニアム響 !ユーフォニアム響け ユーフォニアム響け! ーフォニアム響け!ユ フォニアム響け!ユー ォニアム響け!ユーフ ニアム響け!ユーフォ アム響け!ユーフォニ ム響け!ユーフォニア 響け!ユーフォニアム NIL
関数型っぽくシーケンス処理を書けるので、カッコいいと感じました。これからも使っていきたいです。
疑問
上のコード、実行するたびに以下のようなwarningが出るんですよね。なんとかならないものか。
; in: LET* ((STR "響け!ユーフォニアム") (LEN (LENGTH STR))) ; (ITERATE ((I (SCAN-RANGE :FROM 0 :BY 1 :UPTO LEN))) ; (FORMAT T "~a~%" ; (COLLECT 'STRING ; (SUBSERIES (APPLY #'SERIES #) I (+ I LEN))))) ; ; caught WARNING: ; Warning 28 in series expression: ; (COLLECT 'STRING (SUBSERIES (APPLY #'SERIES (COERCE STR 'LIST)) I (+ I LEN))) ; Non-series to series data flow from: ; (APPLY #'SERIES (COERCE STR 'LIST)) ; to: ; (SUBSERIES (APPLY #'SERIES (COERCE STR 'LIST)) I (+ I LEN)) ; ; compilation unit finished ; caught 1 WARNING condition