あまり Web に日本語で解説のあるサンプルがないようなので、とりあえずで書いてみる。後半に行くほど説明がいいかげんになっているけどご容赦を。

このドキュメントはほぼ SERIES に含まれる、s-doc.txt の抜粋です。

説明書には シーケンス と ストリーム と ループの性質を組合せた物、と記述してあるけど、初めての時は実際に使ってみないと感覚がつかめないかも。

以下のサンプルでは require だけした時の例で書いている。

普通は以下をスクリプトの先頭に書くと series: とかのpackage名を省略できる。あと #Z とか #M が使えるので便利

;; cl-csv となんて組み合せて CSV の処理とか

Series Functions series arg &rest args series を表現するのに #Z(…)の文法が利用されてます。 ;; b と c を繰り返す(永久に出力します) ( series:series 'b 'c ) ;; => #Z(B C B C B C…) ;; まあこれだと使いずらいので、scan を利用します ;; scan は list を series に変換します ( series:scan ( list 'a 'b 'c )) ;; => #Z(A B C) ;; 通常以下のように組合せて利用すると思います ( series:choose-if #' symbolp ( series:scan ( list 'a '2 'b )))

Scanners Scanners は series ではない入力を series に変換します。 scan-range &key (:start 0) (:by 1) (:type 'number) :upto :below :downto :above :length 条件まちがえるとあたりまえですが、永久出力になります。 ;; 0 から 4 以下の series を生成 ( series:scan-range :upto 4 ) ;; => #Z(0 1 2 3 4) ;; 1 から -1 ずつ -4 までの series を生成 ( series:scan-range :from 1 :by -1 :above -4 ) ;; => #Z(1 0 -1 -2 -3) scan {type} sequence sequence を series に変換する。 ;; list を series に変換する ( series:scan ' ( a b c )) ;; => #Z(A B C) ;; 文字列を series に変換する ( series:scan 'string "BAR" ) ;; => #Z(#\B #\A #\R) scan-sublists list list の内容からサブリストを作成する。 ( series:scan-sublists ' ( a b c )) ;; => #Z((A B C) (B C) (C)) scan-multiple type first-sequence &rest more-sequences 複数の sequence を scan する。 ;; 複数 sequence を scan ( series:scan-multiple 'list ' ( 1 6 3 2 8 ) ' ( 2 3 3 3 2 )) ( series:scan-multiple 'string "FOO" "BAR" ) ;; 二つの list を scan して、乗算 ( multiple-value-bind ( data weights ) ( series:scan-multiple 'list ' ( 1 6 3 2 8 ) ' ( 2 3 3 3 2 )) ( series:collect ( series:map-fn t #' * data weights ))) ;; => (2 18 9 6 16) scan-lists-of-lists lists-of-lists &optional leaf-test

scan-lists-of-lists-fringe lists-of-lists &optional leaf-test 複数の list から n-ary tree を生成する。 ( series:scan-lists-of-lists ' (( 2 ) ( nil ))) ;; => #Z(((2) (NIL)) (2) 2 (NIL) NIL) ( series:scan-lists-of-lists-fringe ' (( 2 ) ( nil ))) ;; => #Z(2 NIL) ( series:scan-lists-of-lists-fringe ' (( 2 ) ( nil )) #' ( lambda ( e ) ( numberp ( car e )))) ;; => #Z((2) NIL) scan-alist alist &optional (test #'eql)

scan-plist plist

scan-hash table 連想リスト(alist)、プロパティリスト(plist)、ハッシュテーブルを渡すと、key と value でそれぞれ series に変換する。 ( series:scan-plist ' ( a 1 b 3 )) ;; => #Z(A B), #Z(1 3) ( series:scan-alist ' (( a . 1 ) nil ( a . 3 ) ( b . 2 ))) ;; => #Z(A B), #Z(1 2) scan-symbols &optional (package *package*) symbol を series にします。 ;; series の symbol を取得 ( series:scan-symbols :series ) scan-file file-name &optional (reader #'read)

scan-stream stream &optional (reader #'read) file や stream を series にする。入出力とかの時に便利 ;; ファイルを読んで series に変換 ( series:scan-file "test.txt" #' read-line ) scan-fn type init step &optional test

scan-fn-inclusive type init step test 高階関数な scan。 ;; 二つずつ null になるまで取りだし ( series:scan-fn t #' ( lambda () ' ( a b c d )) #' cddr #' null ) ;; => #Z((A B C D) (C D)) ;; フィボナッチ数列 ( series:scan-fn ' ( values integer integer ) #' ( lambda () ( values 1 0 )) #' ( lambda ( i sum ) ( values ( + i 1 ) ( + sum i )))) ;; => #Z(1 2 3 4 ...), #Z(0 1 3 6 ...)

Mapping map-fn type function &rest series-inputs 高階関数な map。 ;; 足し算 ( series:map-fn 'integer #' + ( series:scan ' ( 1 2 3 )) ( series:scan ' ( 4 5 ))) ;; => #Z(5 7) ;; 分数割り算と余り ( series:map-fn ' ( values integer rational ) #' floor ( series:scan ' ( 1/4 9/5 12/3 ))) ;; => #Z(0 1 4), #Z(1/4 4/5 0) mapping ({({var | ({var}*)} value)}*) {declaration}* {form}* 以下のような感じ。 ;; mapping と map-fn ( mapping (( x r ) ( y s )) ... ) == ( map-fn t #' ( lambda ( x y ) ... ) r s ) ;; mapping の例 ( series:mapping (( x ( series:scan ' ( 2 -2 3 )))) ( expt ( abs x ) 3 )) ;; => #Z(8 8 27) iterate ({({var | ({var}*)} value)}*) {declaration}* {form}* declaration を iterate する。 ( let (( item ( series:scan ' (( 1 ) ( -2 ) ( 3 ))))) ( series:iterate (( x ( series:map-fn T #' car item ))) ( if ( plusp x ) ( prin1 x )))) ;; => NIL (その後に 13 が表示される)

Truncation and Other Simple Transducers cotruncate &rest series-inputs

until bools &rest series-inputs

until-if pred &rest series-inputs ;; 同じ項目数にする ( series:cotruncate ( series:scan ' ( 1 2 -3 4 )) ( series:scan ' ( a b c ))) ;; => #Z(1 2 -3), #Z(A B C) ;; t になるまで ( series:until ( series:scan ' ( nil nil t nil )) ( series:scan ' ( 1 2 -3 4 )) ( series:scan ' ( a b c ))) ;; => #Z(1 2), #Z(A B) ;; 条件になるまで ( series:until-if #' minusp ( series:scan ' ( 1 2 -3 4 )) ( series:scan ' ( a b c ))) ;; => #Z(1 2), #Z(A B) previous items &optional (default nil) (amount 1) 右にシフトさせる ;; シフトさせて 0 で埋める ( series:previous ( series:scan ' ( 10 11 12 )) 0 ) ;; => #Z(0 10 11) latch items &key :after :before :pre :post ラッチ回路の動作をする。 ( series:latch ( series:scan ' ( nil c nil d e ))) ;; => #Z(NIL C NIL NIL NIL) ( series:latch ( series:scan ' ( nil c nil d e )) :before 2 :post t ) ;; => #Z(NIL C NIL T T) collecting-fn type init function &rest series-inputs 高階関数。 ;; 入力した series を加算している。フィボナッチ数列 ( series:collecting-fn 'integer #' ( lambda () 0 ) #' + ( series:scan ' ( 1 2 3 ))) ;; => #Z(1 3 6) ;; 加算と乗算 ( series:collecting-fn ' ( values integer integer ) #' ( lambda () ( values 0 1 )) #' ( lambda ( sum prod x y ) ( values ( + sum x ) ( * prod y ))) ( series:scan ' ( 4 6 8 )) ( series:scan ' ( 1 2 3 ))) ;; => #Z(4 10 18), #Z(1 2 6)

Conditional and Other Complex Transducers choose bools &optional (items bools)

choose-if pred items 条件を与えて選択する。 ;; t になっている物を選択 ( series:choose ( series:scan ' ( t nil t nil )) ( series:scan ' ( a b c d ))) ;; => #Z(A C) ;; プラスの値だけ選択して加算 ( series:collect-sum ( series:choose-if #' plusp ( series:scan ' ( -1 2 -3 4 )))) ;; => 6 expand bools items &optional (default nil) choose の準逆元 (quasi-inverse)。 ( series:expand ( series:scan ' ( nil t nil t t )) ( series:scan ' ( a b c ))) ;; => #Z(NIL A NIL B C) ( series:expand ( series:scan ' ( nil t nil t t )) ( series:scan ' ( a ))) ;; => #Z(NIL A NIL) spread gaps items &optional (default nil) expand は boolean で条件を与えるが、spread は gaps で条件を与えるのが違う。動作はほぼ同じ。 ;; 1 ずつ 間を NIL で埋める ( series:spread ( series:scan ' ( 1 1 1 )) ( series:scan ' ( a b c ))) ;; => #Z(NIL A NIL B NIL C) ;; 0 2 3 で 間を NIL で埋める ( series:spread ( series:scan ' ( 0 2 3 )) ( series:scan ' ( a b c ))) ;; => #Z(A NIL NIL B NIL NIL NIL C) ;; gaps の項目数で終了となる ( series:spread ( series:scan ' ( 2 )) ( series:scan ' ( a b c ))) ;; => #Z(NIL NIL A) split items &rest test-series-inputs

split-if items &rest test-predicates 分割する。 ;; boolean を与えて分割する ( series:split ( series:scan ' ( -1 2 3 -4 )) ( series:scan ' ( t nil nil t ))) ;; => #Z(-1 -4), #Z(2 3) ;; 条件を与えて分割。この例では分割した結果をそれぞれ足している ( multiple-value-bind ( +x -x ) ( series:split-if ( series:scan ' ( -1 2 3 -4 )) #' plusp ) ( values ( series:collect-sum +x ) ( series:collect-sum -x ))) ;; => 5, -5 catenate &rest series-inputs 二つ以上の series を一つに結合する。 ( series:catenate ( series:scan ' ( b c )) ( series:scan ' ()) ( series:scan ' ( d ))) ;; => #Z(B C D) subseries items start &optional below 引数によって series を抽出。 ;; 1 から取り出し ( series:subseries ( series:scan ' ( a b c d )) 1 ) ;; => #Z(B C D) ;; 1 から 3 まで取り出し ( series:subseries ( series:scan ' ( a b c d )) 1 3 ) ;; => #Z(B C) positions bools nil でない項目の index を series として返す ( series:positions ( series:scan ' ( t nil t 44 ))) ;; => #Z(0 2 3) mask monotonic-indices ( series:mask ( series:scan ' ())) ;; => #Z(NIL NIL ...) ( series:mask ( series:scan ' ( 0 2 3 ))) ;; => #Z(T NIL T T NIL NIL ...) ( series:mask ( series:positions ( series:scan ' ( nil a nil b nil )))) ;; => #Z(NIL T NIL T NIL ...) mingle items1 items2 comparator 二つの series を結合し、 comparator にしたがってソートする。 ( series:mingle ( series:scan ' ( 1 3 7 9 )) ( series:scan ' ( 4 5 8 )) #' < ) ;; => #z(1 3 4 5 7 8 9) ( series:mingle ( series:scan ' ( 1 7 3 9 )) ( series:scan ' ( 4 5 8 )) #' < ) ;; => #z(1 4 5 7 3 8 9) chunk m n items n 個飛しで、m 回 items を分割する。 ;; 単純分割のサンプル ( series:chunk 1 1 ( series:scan ' ( 1 5 3 4 5 6 ))) ;; => #Z(1 5 3 4 5 6) ( series:chunk 2 1 ( series:scan ' ( 1 5 3 4 5 6 ))) ;; => #Z(1 5 3 4 5), #Z(5 3 4 5 6) ( series:chunk 3 1 ( series:scan ' ( 1 5 3 4 5 6 ))) ;; => #Z(1 5 3 4), #Z(5 3 4 5), #Z(3 4 5 6) ( series:chunk 1 2 ( series:scan ' ( 1 5 3 4 5 6 ))) ;; => #Z(1 3 5) ;; 分割して、計算 ( series:mapping ((( xi xi+1 xi+2 ) ( series:chunk 3 1 ( series:scan ' ( 1 5 3 4 5 6 ))))) ( / ( + xi xi+1 xi+2 ) 3 )) ;; => #Z(3 4 4 5) ;; 分割して cons ( series:collect ( series:mapping ((( prop val ) ( series:chunk 2 2 ( series:scan ' ( a 2 b 5 c 8 ))))) ( cons prop val ))) ;; => ((A . 2) (B . 5) (C . 8))

Collectors series から list 等の非 series に変換する。 collect-first items &optional (default nil)

collect-last items &optional (default nil)

collect-nth n items &optional (default nil) first,last,nth して返す。 ( series:collect-first ( series:scan ' ()) 'z ) ;; => Z ( series:collect-last ( series:scan ' ( a b c ))) ;; => C ( series:collect-nth 1 ( series:scan ' ( a b c ))) ;; => B collect-length items series の要素数を返す。 ( series:collect-length ( series:scan ' ( a b c ))) ;; => 3 collect-sum numbers &optional (type 'number) 入力した series の elements を加算する。空の場合は 0 を返す ( series:collect-sum ( series:scan ' ( 1.1 1.2 1.3 ))) ;; => 3.6 ( series:collect-sum ( series:scan ' ()) 'complex ) ;; => 0 collect-product numbers &optional (type 'number) series の elements を乗算する。空の場合は 1 を返す。 ( series:collect-product ( series:scan ' ( 1.1 1.2 1.3 ))) ;; => 1.716 ( series:collect-product ( series:scan ' ()) 'float ) ;; => 1.0 collect-max numbers &optional (items numbers) (default nil)

collect-min numbers &optional (items numbers) (default nil) 最大値、最小値を取得する。 ( series:collect-max ( series:scan ' ( 2 1 4 3 ))) ;; => 4 ( series:collect-min ( series:scan ' ( 1.2 1.1 1.4 1.3 ))) ;;=> 1.1 ( series:collect-min ( series:scan ' ())) ;; => NIL collect-and bools series の elements を AND 演算した結果が返る。要素が一つでも NIL なら NIL になる。 ( series:collect-and ( series:scan ' ( a b c ))) ;; => C ( series:collect-and ( series:scan ' ( a nil c ))) ;; => NIL collect-or bools series の elements を OR 演算した結果が返る。最初の NIL でない要素が返る。空の場合は NIL が返る。 ( series:collect-or ( series:scan ' ( nil b c ))) ;; => B ( series:collect-or ( series:scan ' ())) ;; => NIL collect items

collect type items series を sequence に変換する。標準は list。type で指定できる。 ( series:collect ( series:scan ' ( a b c ))) ;; => (A B C) ( series:collect ' ( vector integer 3 ) ( series:scan ' ( 1 2 3 ))) ;; => #(1 2 3) collect-append sequences

collect-append type sequences series を結合して sequence に変換する。type で型を指定できる。標準は list。 ( series:collect-append ( series:scan ' (( a b ) nil ( c d )))) ;; => (A B C D) ( series:collect-append 'string ( series:scan ' ( "a " "big " "cat" ))) ;; => "A BIG CAT" collect-ignore lists collect と内部動作は同じだが、結果は破棄される。遅延評価なので必要になる。ちょっとした所で便利。 collect-nconc lists 結果と同時に series の elements が取れる以外は collect-append と動作は同じ。 collect-alist keys values

collect-plist keys values

collect-hash keys values &key :test :size :rehash-size :rehash-threshold alist、plist、hash に変換する。 ( series:collect-alist ( series:scan ' ( a b c )) ( series:scan ' ( 1 2 ))) ;; => ((B . 2) (A . 1)) ( series:collect-hash ( series:scan ' ()) ( series:scan ' ( 1 2 )) :test #' eq ) ;; => <an empty hash table> collect-file file-name items &optional (printer #'print)

collect-stream stream items &optional (printer #'print) ファイルやストリームに series を出力。 collect-fn type init function &rest series-inputs 高階関数。 ( series:collect-fn 'integer #' ( lambda () 0 ) #' + ( series:scan ' ( 1 2 3 ))) ;; => 6 ( series:collect-fn 'integer #' ( lambda () 0 ) #' + ( series:scan ' ())) ;; => 0

Alteration of Series alter destinations items 特定の位置の elements を変更する ( let* (( data ( list 1 -2 3 4 -5 6 )) ( x ( series:choose-if #' minusp ( series:scan data )))) ;; この時点で x は #Z(-2 -5) ( series:alter x ( series:map-fn t #' * x x )) data ) ;; => (1 4 3 4 25 6) to-alter items alter-fn &rest args ( defun scan-list ( list ) ( declare ( optimizable-series-function )) ( let (( sublists ( series:scan-sublists list ))) ( series:to-alter ( series:map-fn t #' car sublists ) #' ( lambda ( new parent ) ( setf ( car parent ) new )) sublists )))

Generators generator series

next-in generator {action}* generator と next-in を利用してループ等する。便利。 generator はジェネレータを読む。説明は割愛。 ( let (( x ( series:generator ( series:scan ' ( 1 2 3 4 ))))) ( with-output-to-string ( s ) ( loop ( prin1 ( series:next-in x ( return )) s ) ( prin1 ( series:next-in x ( return )) s ) ( princ "," s )))) ;; => "12,34,"