lispとrubyとpythonと その3 リスト(lisp series-scanners)
Lisp、series-scanners編
リファレンスを見ながらseriesのメソッド一通りみてみた。
Alterationはよくわかんなかったので飛ばしたけど。
えらく長いのでエントリを分けます。
まずはscannersから。
;;seriseを使えるようにする (require 'series) (series::install) ;;scannersは非seriesなinputをもらってseriesを返す ;;series関数 ;;なんかおかしい?? ;;ヘルプには ;;(SERIES 'B 'C) => #Z(B C B C B C ...) ;;って書いてある ;;無限リストをつくっちゃうので、 ;;(subseries (series 'b 'c) 0 5) ;;で ;;#Z(B C B C B) ;;になるのかなと思ったんだけど、SBCLですると (subseries (series 'b 'c) 0 5) ;;#Z(LIST B C LIST B) ;;こうなっちゃう・・・ ;;scan-range ;scan-rangeでの生成 ;;http://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node350.html#SECTION003421000000000000000 ;;scan-range &key (:start 0) (:by 1) (:type 'number):upto :below :downto :above :length ;;:fromが書いてない・・・ ;;:startって:fromの間違い? (format t "~A~%" (scan-range :upto 5)) ;;#Z(0 1 2 3 4 5) (format t "~A~%" (scan-range :below 5)) ;;#Z(0 1 2 3 4) (format t "~A~%" (scan-range :from 10 :downto 5 :by -1)) ;;#Z(10 9 8 7 6 5) (format t "~A~%" (scan-range :from 10 :above 5 :by -1)) ;;#Z(10 9 8 7 6) (format t "~A~%" (scan-range :from .5 :by .1 :upto 1 :type 'float)) ;;#Z(0.5 0.6 0.70000005 0.8000001 0.9000001) ;;無限リストなので評価しないように注意 (setf s0 (scan-range)) ;;#Z(0 1 2 3...) ;;scan (format t "~A~%" (scan '(a b c))) (format t "~A~%" (scan 'string "abcdefg")) ;;scan-sublists (format t "~A~%" (scan-sublists '(a b c d e))) ;;#Z((A B C D E) (B C D E) (C D E) (D E) (E)) ;;scan-multiple ;;数があってないぶんはnilを補うみたい (multiple-value-bind (s0 s1) (scan-multiple 'list '(a b c d e) '(1 2 3)) (format t "~A~%" s0) (format t "~A~%" s1)) ;;#Z(A B C D E) ;;#Z(1 2 3 NIL NIL) ;;scan-lists-of-lists ;;ノードをたぐってseriesに追加 ;;scan-lists-of-lists-fringeはノード全体ではなくリーフのみ追加 ;;ツリーをフラットにしてくれる感じ (format t "~A~%" (scan-lists-of-lists '(1 (2 3)))) ;;#Z((1 (2 3)) 1 (2 3) 2 3) (format t "~A~%" (scan-lists-of-lists-fringe '(1 (2 3)))) ;;#Z(1 2 3) ;;NIL ;; リストのたぐり方はこんな感じなんだと思う (defun my-scan-lists-of-lists(lst) (if (not lst) nil (append (list lst) (my-scan-lists-of-lists-a lst)))) (defun my-scan-lists-of-lists-a(lst) (if (or (not lst) (atom lst)) nil (let ((hd (car lst)) (bd (cdr lst))) (append (list hd) (my-scan-lists-of-lists-a hd) (my-scan-lists-of-lists-a bd))))) (defun my-scan-lists-of-lists-fringe(lst) (cond ((null lst) nil) ((atom lst) (list lst)) (t (let ((hd (car lst)) (bd (cdr lst))) (append (my-scan-lists-of-lists-fringe hd) (my-scan-lists-of-lists-fringe bd)))))) ;; CL-USER> (scan-lists-of-lists '((1 2) 3 (4 (5 (6 7) 8) 9) 10)) ;; #Z(((1 2) 3 (4 (5 (6 7) 8) 9) 10) (1 2) 1 2 3 (4 (5 (6 7) 8) 9) 4 (5 (6 7) 8) 5 (6 7) 6 7 8 9 10) ;; CL-USER> (my-scan-lists-of-lists '((1 2) 3 (4 (5 (6 7) 8) 9) 10)) ;; (((1 2) 3 (4 (5 (6 7) 8) 9) 10) (1 2) 1 2 3 (4 (5 (6 7) 8) 9) 4 (5 (6 7) 8) 5 (6 7) 6 7 8 9 10) ;; CL-USER> (scan-lists-of-lists-fringe '((1 2) 3 (4 (5 (6 7) 8) 9) 10)) ;; #Z(1 2 3 4 5 6 7 8 9 10) ;; CL-USER> (my-scan-lists-of-lists-fringe '((1 2) 3 (4 (5 (6 7) 8) 9) 10)) ;; (1 2 3 4 5 6 7 8 9 10) ;;scan-alist ;;キーとvalueのシリーズに分ける (multiple-value-bind (key val) (scan-alist '((a . 1) (b . 2) (c . 3) (d . 4))) (print key) (print val)) ;;結果 ;;#Z(A B C D) ;;#Z(1 2 3 4) ;;(属性 値 属性 値・・・ ;;で並んでるのってplistっていうのね ;;alistしかしらなんだ (multiple-value-bind (key val) (scan-plist '(1 2 3 4 5 6 7)) (print key) (print val)) ;;結果 ;; #Z(1 3 5 7) ;; #Z(2 4 6 NIL) ;;ついで ;;symbol-plist ;;おぼえとくこと (setf ht (make-hash-table)) (setf (gethash "key1" ht) "data1") (setf (gethash "key2" ht) "data2") (setf (gethash "key3" ht) "data3") (setf (gethash "key4" ht) "data4") (multiple-value-bind (key val) (scan-hash ht) (print key) (print val)) ;;結果 ;; #Z("key4" "key3" "key2" "key1") ;; #Z("data4" "data3" "data2" "data1") ;;scan-symbols ;;シンボルをseriesでかえしてくれるみたいなんだけど使いどころが分からん (scan-symbols :cl-user) ;;結果 ;; #Z(RESET UNPROFILE REPORT PROFILE ・・・(略)) ;;scan-file ;;ファイルを読み込んで行を要素にしたseriesを返すみたい ;;これは便利かも (scan-file "./a.txt") #Z(あああ いいい ううう えええ おおお かかか ききき くくく けけけ こここ) ;;scan-fn ;; 引数は ;; SCAN-FN TYPE INIT STEP &optional TEST ;; TYPEで作るseriesの型を決める ;; valuesで複数指定もできる ;; INITで初期値を作る関数を指定 ;; こっちも複数指定するときはvaluesで ;; STEPは次の値を作る関数指定 ;; こっちも複数指定するときはvalues ;; TESTは終了条件 ;; 単純な例 (subseries (scan-fn 'integer #'(lambda () 0) #'(lambda (i) (1+ i))) 0 10) ;;無限リストになるからsubseriesで絞る ;; 結果 ;; #Z(0 1 2 3 4 5 6 7 8 9) ;; 終了条件を指定してみる (scan-fn 'integer #'(lambda () 0) #'(lambda (i) (1+ i)) #'(lambda (i) (> i 3))) ;;継続条件じゃなくて終了条件なので注意 ;; 結果 ;; #Z(0 1 2 3) ;;valuesで複数のseriesを返す (multiple-value-bind (num str) ;;多値が返るからmultiple-value-bindで受ける (scan-fn '(values integer string) ;;valusごとquoteするのに注意 #'(lambda () (values 0 "value+0")) #'(lambda (i s) (let ((i (1+ i))) (values i (format nil "value+~A" i))))) (format t "~A~%" (subseries num 0 10)) (format t "~A~%" (subseries str 0 10))) ;; 結果 ;; #Z(0 1 2 3 4 5 6 7 8 9) ;; #Z(value+0 value+1 value+2 value+3 value+4 value+5 value+6 value+7 value+8 value+9) ;; ファイルを読んでindexをつけてみた。 (with-open-file (strm "./a.txt") (multiple-value-bind (idx line) (scan-fn '(values integer string string) #'(lambda () (let ((line (read-line strm nil 'eof))) (values 0 (format nil "0:~A~%" line) line))) #'(lambda (i fl l) (let ((line (read-line strm nil 'eof))) (values (1+ i) (format nil "~A:~A~%" i line) line))) #'(lambda (i fl l) (eql l 'eof))) (format t "~A~%" idx) (format t "~A~%" line))) ;; 結果 ;; #Z(0 1 2 3 4 5 6 7 8 9) ;; #Z(0:あああ ;; 0:いいい ;; 1:ううう ;; 2:えええ ;; 3:おおお ;; 4:かかか ;; 5:ききき ;; 6:くくく ;; 7:けけけ ;; 8:こここ ;; ) ;; SCAN-FN-INCLUSIVE ;; よくわかんない ;; INITが返した要素をTESTでテストしない、という以外はscan-fnと同じ?? (scan-fn-inclusive 'integer #'(lambda () 0) #'(lambda (i) (1+ i)) #'(lambda (i) (< i 3))) ;; 結果 ;; #Z(0)