2018年7月30日月曜日

branchって便利

 いったん動いているプログラムはあまり、いじりたくない。
 elispならとくにそうで、プログラムがEmacsで動作するのでロードエラーがでるような状態にしてしまうと、通常の業務1に支障がでてしまう。というわけで、なおしたいなぁ、と思っていても放っておいてしまっていた。

 でもgitのbranchを使えば、いいんじゃね?
 新しいbranchを切ってそちらで修正をしておいて必要になったら。

git checkout master

 で、元にもどせば、いい。
 同じようなことはsubversionでもできたはずなのだけど、全然、思いつきもしなかった。何をやっておるのか。

 というわけでこれからがんがん、プログラムがいじれる。
 いじれるはず。
 いじらないけど。

Footnotes:

1

何の業務だ?

2018年7月28日土曜日

slime-scratch

 REPLって便利なんだけど、Emacsのscratchバッファになれているせいか、どうも使いづらい。scratshバッファは平面だけど、REPLは一次元ということがあるのだろう。
 ダミーのlispファイルをひらいてそのバッファでコードを書いて——実際の動作はREPLで確認、ということをやっていた。
 slimeの関数を眺めていたらslime-scratchというのを見つけた。
 おっ。

2018年7月26日木曜日

スターン数列とフィボナッチ数

スターン数列は,f(0)=0、f(1)=1と二つの再帰的関係f(2n)=f(n)およびf(2n+1)=f(n)+f(n+1)で定義される.これを計算すると,数列は0,1,1,2,1,3,2,1,4,3,5,2,5,3,4と続く.

マーク・チャンバーランド「ひとけたの数に魅せられて」 P11

 何をいっているのか、わからない。

 スターン数列でググってみたけれど、ヒットしたサイトは本の説明をくりかえしているだけで何のとっかかりにもならなかった。日本語のwikiも見当たらない。
 まぁ、f(0)とf(1)はわかる。でもf(2n)=f(n)って何だ? イコールじゃないじゃないか。
 しばし、じっと見つめる。
 あれ?
 もしかしたらf(2n)って偶数のことじゃないか?
 すると、f(2n+1)は奇数か。
 じゃ、コードはこうか?

(require 'cl)

(defun wrk(n)
  (cond ((= n 0) 0)
 ((= n 1) 1)
 ((evenp n)(wrk (/ n 2)))
 ((oddp n)(+ (wrk (/ n 2))(wrk (+ (/ n 2) 1))))))

(mapcar 'wrk '(0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15))
(0 1 1 2 1 3 2 3 1 4 3 5 2 5 3 4)

 おっ、正しいみたいだぞ1
 プログラミングができてよかった。
 エレン、マフラーを巻いてくれてありがとうって気分だ。

 そういえば、フィボナッチ数のコードはよく見かけるけど2、実際に自分で組んでみたことはなかった。たしか、こんな感じ?

(defun wrk(n)
  (cond ((= n 0) 0)
 ((= n 1) 1)
 (t (+ (wrk (- n 1))(wrk (- n 2))))))

(mapcar 'wrk '(0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15))
(0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610)

 0から15ぐらいならすぐだけど、0から100までにしたら延々、もどってこない……。

Footnotes:

1

by elisp

2

再帰の例題としては定番。

2018年7月24日火曜日

竹内郁雄「初めての人のためのLISP」

 もっと早くに読んでおくべきだった。
 交互リストによるplistのことも書かれているし、keywordについても——CommonLispをはじめていろいろ疑問に思ったことの答えが書かれていた。
 もっともずっと以前に読んでいたらこれらのことは気づかずにふーんとスルーしていたにちがいないけど。

2018年7月22日日曜日

setf

 setfではassocを使えないんだね1

CL-USER> wrk
((1 2) (3 4) (5 6))
CL-USER> (setf (assoc 3 wrk) 123)
; Evaluation aborted on #<UNDEFINED-FUNCTION (SETF ASSOC) {1003D452D3}>.
CL-USER>

 でもこうすると、中身を変更できるんだ。

CL-USER> wrk
((1 2) (3 4) (5 6))
CL-USER> (setf (cadr (assoc 3 wrk)) 99)
99
CL-USER> wrk
((1 2) (3 99) (5 6))
CL-USER>

 これまた、RDBっぽい。
 ちなみにまちがって下記のように書いたらSBCLは即エラーになったけれど、ABCLは永久ループにはまりこんでしまった。

CL-USER> wrk
((1 2) (3 4) (5 6))
CL-USER> (setf (cadr (assoc 3 wrk)) wrk)

 elispはどうだろう。

(setf wrk '((1 2)(3 4)(5 6)))
((1 2) (3 4) (5 6))
(setf (cadr (assoc 3 wrk)) wrk)
((1 2) (3 #0) (5 6))
wrk
((1 2) (3 #0) (5 6))

 なんじゃ?

Footnotes:

1

setfできるassocがalexandriaにあるらしい。

2018年7月20日金曜日

delete

 listを操作する関数で破壊的なものはあまり使う気になれなかった。意外なところに影響がでたりするからだ。でもsetfは便利だな、と思っていて、そういえば、listの一部だけ削除するにはどうしたらいいんだろう。
 deleteを見つけて色々、試してみて思った。
 これってassocと組み合わせるとすごくね?

CL-USER> wrk
((1 2) (3 4) (5 6))
CL-USER> (delete (assoc 3 wrk) wrk)
((1 2) (5 6))
CL-USER> wrk
((1 2) (5 6))
CL-USER>

 RDBみたいじゃん。
 deleteのような破壊的関数ではなく、removeというのもあった。

CL-USER> wrk
((1 2) (3 4) (5 6))
CL-USER> (setq wrk2 (remove (nth 1 wrk) wrk))
((1 2) (5 6))
CL-USER> wrk
((1 2) (3 4) (5 6))
CL-USER> wrk2
((1 2) (5 6))
CL-USER>

 もしかしたら、と思って試してみたら。
 wrkとwrk2の要素は共有されていた。

CL-USER> (setf (caar wrk2) 123)
123
CL-USER> wrk
((123 2) (3 4) (5 6))
CL-USER> wrk2
((123 2) (5 6))

 おもしろい。
 elispでも同じことができるけど、deleteの比較はequalだった。eqのものはdelq。CommonLispはどうやらeqらしい。:testで変更できるけど。

2018年7月19日木曜日

2018年7月16日(月):検見川浜:晴れ

* Sail:CORE 5.7(NEIL PRYDE) Board:NG ACP 260 Fin:9.5inch

No 時刻 時間 帆走距離 最高速 平均時速 P%
1R 14:21-14:43 21分 2.9km 19.92km/h 7.85km/h 3.87
2R 15:03-15:32 28分 4.1km 31.47km/h 8.56km/h 5.89
3R 16:04-16:17 13分 1.3km 17.55km/h 5.43km/h 0.43

total 64分 8.2km 7.6km/h

 ほんとうは海へ行くつもりはなかった。
 GPVを見るかぎり、昨日より吹くとは思えない。昨日ですら微妙だったのだ。だから昨日、検見川へ行ったのに、今日も来てしまった。入庫待ちの車の列に並ぶ。さすがに昨日よりも早めだったので時間がかかってしまう。
 風は微妙。いや無理だろう。
 デカスラは走っているけれど。
 夕方のひと吹きを期待して海へでる。だめ。腹が立つのは自分が海からあがると、急に吹き出して走り出したように見えることだ。もちろん錯覚だ。そもそもプレーニングしている人間と自分が同じ腕前という前提がまちがっている。
 というわけで本日、プレーニングしたのは一本だけだった。

2018年7月18日水曜日

2018年7月15日(日):検見川浜:晴れ

Sail:CORE 5.7(NEIL PRYDE) Board:NG ACP 260 Fin:9.5inch

No 時刻 時間 帆走距離 最高速 平均時速 P%
1R 14:45-15:02 17分 1.5km 31.23km/h 5.07km/h 3.19
2R 15:06-15:18 12分 1.3km 19.62km/h 6.60km/h 2.28
3R 15:44-16:50 65分 8.4km 35.21km/h 7.74km/h 8.88
4R 17:07-17:23 16分 2.5km 34.69km/h 9.07km/h 13.72

total 111分 13.8km 7.4km/h

 30分待ちで駐車場に入れることができた。
 途中、道路から見える検見川浜は沖でデカスラっぽいセイルが走っていた。微妙に足りないんだろうなぁ、と思っていたら案の定で微妙に足りない風——ブローも微妙。
 スタボーはうねりにあわせてなんとか、プレーニングすることもあったけれど。ポートは乗り方を忘れていることもあってほぼ全滅。それでも二度ほどプレーニングした。
 ジャイブは、何それ、おいしいの? 状態。
 二時すぎにあった風はいったん落ちて五時ぐらいにやや強くなる。
 気温が下がって風が重くなったのかもしれない。
 夏の検見川浜のサーマルははじめてだったけれど、もうすこし大きめのサイズがないときびしいなぁ。
 それにしても身体が動かない。
 晩年の岡部幸雄のようにストレッチをした方がいいんだろうなぁ。

2018年7月17日火曜日

slime-eval

 CommonLispを使うようになってelispをプログラミングする気力がなくなってしまった。
 別にLisp四天王でelispが一番、最弱だから、というわけではなく、CommonLisp——SBCL——のレスポンスが速くてelispを使う気がしなくなってしまったのがひとつ。もうひとつは別プロセスで動くので、Emacsがかたまるということがない。こっちの方が理由としては大きいかもしれない。
 ただ、やはりエンドユーザとのインターフェイスをもっているというのは大きくてなんだかんだと選択肢はelispということになってしまう。
 じゃあバックグランドでCommonLispを動かしてしまえば、いいじゃん。
 S式でやりとりできるだろうし。
 roswellスクリプトをshell-commandで起動して……とか、考えて面倒くさっ、と思ってしまった。もっと簡単にできないものか。

 そもそもEmacsとCommonLispでやりとりしているわけだし。
 ——slimeに何か、あるんじゃね?
 そう思ってつらつらslimeのソースをながめていたら。
 「slime-eval」というものを見つけた。
 slimeを動かして*scratch*で——。

(slime-eval `(cl-user::+ 1 2 3))
6

 おおっ。
 eval自体はSWANK-IO-PACKAGEの中で動いているらしく、packageをフル指定しなければ、ならなかったけれど。
 listだって返ってくる。

(setq wrk (slime-eval `(cl-user::list 1 2 3)))
(1 2 3)
(car wrk)
1

 elispとシームレスにやりとりできるじゃないか!
 しかも非同期バージョンと思しき、「slime-eval-async」もある。
 「asdf::load-system」だってelispから動かせる。

 しかし、elispの変数の中身をわたすには——。

(setq wrk 4)
4
(setq wrk (slime-eval `(cl-user::list 1 2 3 ,wrk)))
(1 2 3 4)

 こうか。
 それにしてもこのやり方ってlispにしか、できない芸当だよなぁ1

Footnotes:

1

shellもできるか……。

2018年7月15日日曜日

(unintern 'function)

 けっこうdefmethodが好きだ。
 引数の型によって処理をディスパッチできるので同じ名称をつけることができる。ただ、REPLでdefunで定義したものをあらためてdefmethodにしようとするエラーになってしまう1。いちいち、restartさせなければ、ならず……ああ?
 まてよ、所詮、シンボル。
 もしかしたら。

(unintern 'function)

 で、いけるんじゃね?
 defmethodで定義できるようになるんじゃね?
 ——いけた2

Footnotes:

1

SBCLだけ?

2

追記。いけたと思っていたのだけど、だめなケースもあるみたいで
方法を探してみたところ

(fmakunbound 'function)

で、できるらしい。

2018年7月13日金曜日

nilってほんとうにNULLなのか!

 けっこうdefmethodが好きだ。
 というのも引数によって処理を分岐する関数をつくることが多いから。
 たとえば(下記はelispだけど)。

(defun y-string-to(x)
  "stringへ変換"
  (cond ((null x) "")
 ((listp x)(y-string-to (car x)))
 ((symbolp x)(y-string-to (symbol-name x)))
 ((stringp x) x)
 ((numberp x) (number-to-string x))
 ((vectorp x)(y-string-to (aref x 0)))))

 とか。
 defmethodを使えば、これらは全部、分けられる。

(defmethod y-string-to((x string))
      x)

(defmethod y-string-to((x number))
      (format nil "~D" x))

 とか。でもstringでもnumberでもないnilのときはどうすれば、いいねん、と思っていたら定義できるのだった。

(defmethod y-string-to((x null))
      "")

 nilってNULLってタイプなのか!

DEF> (type-of nil)
NULL
DEF>

2018年7月11日水曜日

Lispに型はないと思っていたら

 どうしてか、Lispには型がないとばかり思っていた。
 さすがに文字列と数値とかはあるだろうけど、と。

DEF> (type-of :ABC)
KEYWORD
DEF>

 ってやってみて驚いた。
 「:」付きってkeywordという型をなのか。
 あるじゃないか。型。
 以前からよくわからなかった「:」はkeywordという型指定ということになるのか、つまり。もしかしたらリーダーマクロで実装されているんだろうか?

 というか、根本的に勘違いしているじゃないか。

Lispはプログラムの実行時まで呼び出すべき変数のデータ型や関数の実体が決まらない動的束縛(late bindingともいう)の言語である。

竹内郁雄「初めての人のためのLisp [増補改訂版]」

2018年7月9日月曜日

みたび、package

 たとえば、次のようなpackageとclassを定義したとする。

(in-package :cl-user)

(defpackage abc
  (:use :cl)
  (:export :<abc>))

(in-package :abc)

(defclass <abc> ()
  ((abc :initarg :abc
  :reader get-abc
  :documentation "abc")))

(in-package :cl-user)
(defpackage def
  (:use :cl
 :abc))

(in-package :def)

(defclass <def> (<abc>)
  ((def :initarg :def
  :reader get-def
  :documentation "def")))

 で、defの中でinstanceを作成。

DEF> (setq wrk (make-instance '<def> :abc "111" :def "222"))

 まぁ、WARNINGは多少でるけれど、中身は設定されている。

DEF> (get-def wrk)
"222"
DEF>

 get-abcが効かないのは関数をexportしていないのでDEFから見えていないからだろう。

DEF> (get-abc wrk)
; in: GET-ABC WRK
;     (DEF::GET-ABC DEF::WRK)
; 
; caught STYLE-WARNING:
;   undefined function: GET-ABC
; 
; caught WARNING:
;   undefined variable: WRK
; 
; compilation unit finished
;   Undefined function:
;     GET-ABC
;   Undefined variable:
;     WRK
;   caught 1 WARNING condition
;   caught 1 STYLE-WARNING condition
; Evaluation aborted on #<UNDEFINED-FUNCTION GET-ABC {1003F36EE3}>.
DEF>

 ところがslot-valueでabcの中身を見にいってもエラーになる。

DEF> (slot-value wrk 'def)
"222"
DEF> (slot-value wrk 'abc)
; Evaluation aborted on #<SIMPLE-ERROR "~@<When attempting to ~A, the slot ~S is missing from the ~
   object ~S.~@:>" {10040EC8D3}>.
DEF>

 これがしばらく理解できなかった。
 というのもelispのEIEIOではうまくいくからだ。
 HyperSpecのdefpackageの説明を見ていてexportしているのはsymbol-nameだと気づいた。functionじゃないんだ……。つまりClassの中で定義しているslot-nameもexportしなければ、いけない。
 それならこれでも動くはず。

DEF> (slot-value wrk 'abc::abc)
"111"
DEF>

 実際にexportしてやっても動いた。

(defpackage abc
  (:use :cl)
  (:export :<abc>
    :abc))
DEF> (slot-value wrk 'abc)
"111"
DEF>

 EIEIOで動いていていたのはpackageがないからか……。
 でもslot-nameなんてばりばり競合してしまうでaccessorをexportするのが、吉なんだろうな……。accessorならmethodなので同じ名前が存在しても競合する可能性はきわめて低いから。

2018年7月7日土曜日

git clone

 Beelink S1とMacBook Airとのソースの同期はどうしよう。
 一発目は単純にscpしたけれど、これから色々とめんどうな予感がする。rsync?
 ああ、そうか。どうせMacBook Airのソースはgitで管理しよう、と思っていたんだった。それならBeeLink S1からgit cloneしてやれば、いいのか。

2018年7月6日金曜日

いろいろあかんようになっていた

 さすがに半年以上も放っておくと、色々と壊れてしまうもので。
 アクションカメラでウィンドの動画を撮影していたはずなのに、MicroSDカード壊れていて何も撮影されてなかった。そのうえ、GPSロガーとして使用していたiPhoneのアプリ——ZweiteGPSも以前と使い方が若干、変更されていてセイリング中だけではなく、検見川浜をうろうろしていた時までロギングされてしまった。
 そのログをgpsbabelに喰わせようとしたらgpsbabelが動かない。何? QTのライブラリが見当たらん、とは。そんな子だっけ、きみは。
 さらに自分がつくったelispプログラムの使い方もすっかり忘れていた。
 なんとか、そのあたりを解消したけれど、今度はVikingが動かない……。
 元々、ソースを持ってきてMacBook Airで強引にコンパイルしたものだ。すったもんだしたあげく、リンクしているX関係のライブラリがなくなっているのがわかった。それをなんとか、誤魔化して動くようにしたのだけれど——。
 地図が表示されない。エラー出まくり。
 しかたないので最新版をgit cloneしてきてまた、コンパイル。あれ? 最新版のはずなのにバージョンが1.6だ。嫌な予感。動かしてみると。
 やはり地図が表示されない……。虚しい……。

 OpenStreetMapのデータを取得できなくなっているような感じだ。APIのインターフェースがかわったとか、そんなところかもしれない。ソースをいじる気力はなく、ほかの使えそうなソフトを探す。

 TrailNote:

 登山用のためか、高度のデータの表示はできるけれど、あいにく速度表示はだめっぽい。

 JOSM:

 まぁ、これかな……。
 OpenStreetMapがらみのソフトで最初はこれでいい、と思っていたのだけど、javaをインスールしなければ、ならないので躊躇してしまった。javaをいれたら負け。そんな気持ち。でも背に腹は変えられず、インストールした。悪くはないのだけど、GPSエディタではなく、どうやら地図編集ソフトというべきものだった。
 それにしても画像出力の機能がないことには1頭を抱えてしまった。
 そのあたりはスクリーンキャプチャを使うことで解決したけれど。

Footnotes:

1

プラグインを探せば、あるかもしれないけれど、見つけ切れなかった。

2018年7月5日木曜日

2018年7月1日(日):検見川浜:晴れ

Sail:CORE 5.7(NEIL PRYDE) Board:NG ACP 260 Fin:9.5inch

No 時刻 時間 帆走距離 最高速 平均時速 P%
1R 15:33-16:14 41分 5.6km 32.32km/h 8.03km/h 21.39
2R 16:26-16:46 20分 3.7km 36.81km/h 10.91km/h 32.16
3R 16:58-17:47 49分 4.6km 33.21km/h 5.56km/h 9.53

total 111分 13.8km 7.4km/h

 ウィンドへ行くというのは一日がかりの作業だ。
 朝早くから起きだして車を運転して海、あるいは湖へ——それでも確実に風に当たるとはかぎらない。午後から行ければ、ヤボ用を午前中に済ませることができる。
 距離的に考えて検見川浜ならそれが可能ではないか。
 梅雨明け一週間で土曜と同じくらい吹きそうな日曜だった。筋肉疲労で鬱な気分だったけれど、昼すぎに車を出した。やはり疲れていたのだろう。駐車場が満車になる可能性はまったく頭に浮かばなかった。
 ——「満」
 ありゃあ、そうだよなぁ。
 空きができたら移動しようと、近くにある無料駐車場にいれたけれど、こちらは四時半まで。あまりにも中途半端。空きができたらと思う以前に次々に車がきてしまっている。で、見ていると、それらの車は十分ほどで入場しているじゃないか。
 しまった。
 それが正しい選択だったか。
 あわてて列の後ろに並びなおす。なのにそんなときにかぎってなかなか空きができない。何をやっておるのだ、おれは。来たときにそのまま、我慢していれば、OKだったのに。
 それでもなんとか、入ることができた。
 五時ぐらいには風がなくなる予報だったけれど、昨日よりも風はあった。
 なんとかプレーニングするぐらい。
 しかし、ポート側がむちゃくちゃへたくそになっていてちっともプレーニングに入れなかった……。身体で覚えたことは忘れないなんて絶対、嘘だ……。

2018年7月4日水曜日

2018年6月30日(土):検見川浜:晴れ

1 Sail:CORE 5.7(NEIL PRYDE) Board:NG ACP 260 Fin:9.5inch

No 時刻 時間 帆走距離 最高速 平均時速 P%
1R 11:05-11:27 21分 1.8km 14.07km/h 5.09km/h 0.00
2R 12:17-13:11 53分 2.8km 23.95km/h 3.13km/h 0.71
3R 14:39-15:05 25分 1.2km 20.20km/h 2.89km/h 0.78
4R 15:14-17:07 112分 8.4km 32.91km/h 4.45km/h 6.58

total 212分 14.2km 4.0km/h

 去年の今頃の検見川浜はとても臭かった
 赤潮が発生していて凄まじい生臭さで思わず、Uターンした。吹いていたのに。原因は急激な気温上昇だとか、なんとか。
 もしかしたら今年も同じパターンか。
 どきどきしながら赴いてみると、そんなことはなった。ただひたすら暑い。風はけっこう吹いているように見えた。午後になってから吹くと踏んでいたのだけれど。
 今年初である。
 気持ちはとても後ろ向きだった。何しろ、去年の最後にひどい目にあった場所なのだ——また、同じ目にあったらどうしよう。
 うだうだとセッティングして海へ出た。
 思ったよりも吹いていない。ノープレーニング。そして。去年ひどい目にあったエリアで沈。そのまま、風が足りず、ウォーターもできず。このまま、ブロックへ押し流されたら悪夢ふたたびだ。
 そうなったらおれは泣く。絶対、泣く。
 なんとか、ウォーターできて無事、帰着できた。
 吹いていそうで吹いていない日だった。
 風、来た来た、ずるずるぽっちゃんのくりかえし。
 引き潮が終われば、吹くのではないか。そう思っていたけれど、あまり風は上がらず。なんとかスタボーでうねりにあわせてプレーニングしたくらいだった。
 初回はこんなものか。
 それにしてもまぁ、身体が動かなかったことよ。

2018年7月3日火曜日

Lispには代入文がないんだね

 ふと気づいた。
 そういえば、Lispには代入という概念がないな、と。
 C言語にしろ、javaとかにしろ「=」で変数に値を代入する代入文の記法が存在する。シェルスクリプトにすら、ある。
 それなのにLispにはそういう記法がない。見たことがないだけかもしれないけど——もちろん変数への値の設定する方法としてset系の関数がある。でもそれはあくまでも関数であって、文法で定義されているわけじゃない。
 そもそも変数への値の代入なんて存在しないんじゃないのか?
 あ、そうか。
 シンボルへの値の束縛(bind)ってそういうことか。シンボルに値を紐づけることがLispでの変数への値の設定なのか。なんとなく、C言語のポインタと値の関係が逆転しているような感じだ。
 へー。
 道理で束縛、束縛とマニュアルにでてくるわけだ。

2018年7月1日日曜日

emacs -daemon

 sshで動かしているプログラムはターミナルを閉じると、中断してしまう。これをなんとか、動いたままにできないものか——やり方はいろいろ、あるのだろうが1、今はとりあえず、emacs -daemonをつかっている。

  1. sshでログイン
  2. emacs -daemonでemacsを起動
  3. emacsclientでemacsに接続
  4. emacsでプログラムを動かす
  5. emacsclientを閉じる

 これでemacsの中でプログラムは動いているのでターミナルを閉じてもだいじょうぶ2。そのあと、再度、emacsclientで接続しなおすこともできる。emacs自身に重い処理をさせていると、5.の段階で反応しなくなるけど。
 このときもターミナルを閉じても死ぬのはemacsclientだけだろうからプログラムは実行され続けているんじゃなかろうか……。
 試してないけど。

Footnotes:

1

昔はatコマンドを有効にして時間起動していた。

2

すくなくともslimeで動かしていたlispはだいじょうぶだった。