cal
calというのはある年(ある月)のカレンダーを出力してくれるものである.cal 3 2015
と入力すると
March 2015 Su Mo Tu We Th Fr Sa 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31が出力される. これは文字ベースだが, pcalはPostScriptで出力が得られるものである. 私は自分で書いたpcalも持っている.
2007年の夏のプログラミング・シンポジウムで私は「いろいろなプログラミング言語によるcalのプログラミング」という題でMMIX, Haskell, PostScript, Scheme, Teco, Texでcalを書いた.
GPMを使っていみていると, GPMでもcalを書いてみたくなるのは人情である. で早速やってみた.
まずはSchemeでロジックを確認しよう. ある月のカレンダーを次のように出力するとして, パラメータa, b, cを次のものとする.
(define (pcal a b c) ;0<=a,b<7, 3<=c<6 (define (ss) (display " ")) ;空白3文字出力 (define (dd x y) (display x) (display y) (display " "));xy空白 (define (nn) (newline)) ;改行 (define (r n x y) ;月末処理 最後の行 xyからn回出力 (if (> n 0) (begin (dd x y) (if (= y 9) (r (- n 1) (+ x 1) 0) (r (- n 1) x (+ y 1)))))) (define (q m n x y) ;m行目n曜日にxyを出力 (if (= m 0) (r (- 7 b) x y) ;月末処理へ (begin (dd x y) (cond ((and (= n 0) (= y 9)) (nn) (q (- m 1) 6 (+ x 1) 0)) ((and (= n 0) (< y 9)) (nn) (q (- m 1) 6 x (+ y 1))) ((and (> n 0) (= y 9)) (q m (- n 1) (+ x 1) 0)) ((and (> n 0) (< y 9)) (q m (- n 1) x (+ y 1))))))) (define (p n) ;月初処理 始めの空白日を出力 (if (= n 0) (q c (- 6 a) 0 1) (begin (ss) (p (- n 1))))) (p a) ) (newline) (pcal 3 2 4)@これで上手くいったのでgpmへ書き換える. マクロ中の空白や改行に注意.
$def,pcal,< $def,1+,<$~1, $def,~1,<$1,2,3,4,5,6,7,8,9,10,$def,1,<~>>~1<;;>;, $def, ,1;;>; $def,1-,<$-1,0,1,2,3,4,5,6,7,8,$def,-1,<~>~1;;>; $def,-,<$~2,$def,~2,<$-,$1-,>~1<;,$1-,>~2<;;>;,$def,0,~1;;>; $def,nn, ; $def,ss, ; $def,dd,<~1~2 >; $def,r,<$~1, $def,~1,<$dd,>~2<,>~3<;$>~3<, $def,>~3<,<$r,$1-,>>~1<<;,>>~2<<,$1+,>>~3<<;;>;, $def,9,<$r,$1-,>>~1<<;,$1+,>>~2<<;,0;>;;>;, $def,0,;;>; $def,q,<$~1, $def,~1,<$dd,>~3<,>~4<;$>~2~4<, $def,>~2~4<,<$q,>>~1<<,$1-,>>~2<<;,>>~3<<,$1+,>>~4<<;;>;, $def,>~2<9,<$q,>>~1<<,$1-,>>~2<<;,$1+,>>~3<<;,0;>;, $def,0>~4<,<$nn;$q,$1-,>>~1<<;,6,>>~3<<,$1+,>>~4<<;;>;, $def,09,<$nn;$q,$1-,>>~1<<;,6,$1+,>>~3<<;,0;>;;>;, $def,0,<$r,$-,7,>>~2<<;,>~3<,>~4<;>;;>; $def,p,<$~1, $def,~1,<$ss;$p,$1-,>~1<;;>;, $def,0,<$q,>>~3<<,$-,6,>>~1<<;, ,1;>;;>; $p,~1; >; $pcal,3,2,4;本来のcal, pcalにするには年月をパラメータa,b,cに変換する必要がある. これには400など我々のGPM世界をはみ出す定数が現れるので, 取りあえずはSchemeで書いてある.
年月からpcalのパラメータを求めるプログラム (define (ym2pcal y m) (let* ((p (lambda (n) (= (modulo y n) 0))) (q (lambda (n) (quotient y n))) (s `(0 3 ,(if (if (p 100) (p 400) (p 4)) 1 0) 3 2 3 2 3 3 2 3 2 3)) (d (modulo (- (+ 1 y (q 4) (q -100) (q 400)) (apply + (list-tail s m))) 7)) (z (+ (list-ref s m) 28))) (list d (modulo (- 42 (+ d z)) 7) (quotient (- (+ d z) 1) 7)))) (map (lambda (m) (ym2pcal 2015 m)) (a2b 1 13)) => ((4 0 4) (0 0 3) (0 4 4) (3 2 4) (5 6 5) (1 4 4) (3 1 4) (6 5 5) (2 3 4) (4 0 4) (0 5 4) (2 2 4))$pcal,a,b,cがうまくいったので, 今回はこれで満足しよう.