ラベル CommonLisp の投稿を表示しています。 すべての投稿を表示
ラベル CommonLisp の投稿を表示しています。 すべての投稿を表示

2021年8月17日火曜日

Lisp ECL

 土日にWindowsやらFreeBSDのUPDATEをしてpkgとか、upgradeしてみたらmaximaで使われているCommonLispがSBCLではなくなっていた。

Maxima 5.44.0 http://maxima.sourceforge.net
using Lisp ECL 20.4.24

 なんぞ、これ。

  LISPUSER ECL – Embeddable Common-Lisp

 2007年のものだからちょっと情報は古いかもしれない。versionが0.9.6.2だし。
 ただ、これを読んでいてそんなものがあったな、と思い出した。

2021年6月15日火曜日

pathname

 Windows環境ではなんだかんだとunzipが面倒臭い。
 Emacsから外部アプリケーションを起動してコマンドひとつで、unzipできるようにしているのだけど、外部アプリケーションは非同期で、動いているので、unzipしたあとの作業が自動化しづらい。できなくはないけれど、Emacsから同期してunzipができれば、それが一番だ。
 そこで slime-evalを使ってABCL経由でunzipすることにした。
 ABCLはjavaで作られていることもあって内蔵のunzipがあるのだ。

 で、やってみたら落ちた。
 slime-evalがエラーになっていた。
 ——なんで?
 調べてみると、どうやらABCLのunzipは展開したファイルのlistを返却してくれていてそれが原因らしい。というのもlistの中身はpathnameで「#P"/XXXX/XXX"」みたいになっているのだが、これをelispが解釈できなかった。
 目が点だ。
 pathnameって中身はstringじゃなかったの?

CL-USER> (stringp #P"/tmp/a")
NIL
CL-USER> (pathnamep #P"/tmp/a")
T
CL-USER> 

 ちがう。なんてこった。
 stringに変換する関数を探す。一番、時間がかかった。見つけた。
 ——namestring

CL-USER> (namestring #P"/tmp/a")
"/tmp/a"
CL-USER> 

 これさえあれば、listの中身を一括変換するのはmapcarで一発である。

2020年9月18日金曜日

ループ処理

 C言語を使っていたころはループはforばかりを使っていた。
 それがPerlでforeachを知り、これは良い! と思っていたのだけど。
 最近、javaでforeachループを(forだけど)使っていて、なんか、今いちだなぁ、と。
 CommonLispの loopマクロを知ってしまった今となっては。javaにはどうしてloopマクロがないんだ、と不満がつのってしまう。ストレスを感じる。
 なぜだろう。
 loopマクロだと感覚的にループ処理を書いていると、あまり思ってないような気がする。普通の処理を書いているような感じ。不思議だ。
 たぶんループの中で行なわれる処理と、ループ自体の処理が渾然しているからかもしれない。つながっている。
 forループとかだと、ループ自体の処理と、中の処理を頭の中で意識的に無理してつないでいるような感覚があるんだよな。loopマクロだと、それが自然に書き下していけるような感じ。

2020年8月28日金曜日

nth

 

え?

ええ?

CL-USER> (setf wrk '(1 2 3))
(1 2 3)
CL-USER> (nth 1 wrk)
2
CL-USER> 

そうだったのか!

2020年5月19日火曜日

if文に隠蔽される処理

 たとえば、変数の値によって関数の呼び出しをかえるような処理は、普通のプログラミング言語だと

 if(変数A == 999){
    処理関数(1);
}  else {
    処理関数(2);
}

 みたいな書き方をする。
 もちろん、Lisp系でも同じような書き方ができるけれど

( if (= 変数A 999)
    (処理関数 1)
    (処理関数 2))

 こんな書き方もできる。

(処理関数 ( if (= 変数A 999)
              1
              2))

 後者の方が見易いような気がする。というのも

(処理A)
( if (条件)
    (処理B 1)
    (処理B 2))
(処理C)

 となっていると、if文の中に処理がほんのわずかに隠されて処理の流れが見づらなるような。

(処理A)
(処理B ( if (条件)
           1
           2))
(処理C)

 ね?

2020年5月18日月曜日

mapcarとloop

 elispを独習しはじめたころ、おおっ、と感動したのは「mapcar」の存在だった。
 何を感動したのか、というと、それがループ処理だった、ということ。よくあるバグにループの脱出条件のミスって永久ループしてしまう、というのがあるけれど、これならかならず、終了するじゃないか。なので最初のころ書いたコードは「mapcar」だらけになってしまった。
 ところがある日、そのコードを読み返していて気づいた。
 ——読みづらい。
 「mapcar」の引数は

(mapcar 処理 リストを生成する処理)

 となっているので、処理の順番という意味ではうしろから読み解かなくていけないのだ。
 それが脳みそに余計な負荷をかけている。
 もちろんすぐにloopマクロの存在に気づいて、今ではloopマクロを使いまくりなのだけど。

( loop for x in リストを生成する処理
      collect 処理)

 こちらの方が「リストを生成する処理」「処理」と読んでいけるのでものすごく楽。
 今や「mapcar」はワンラインで書けるサイズでないと、書く気がしない、という。

2020年3月5日木曜日

dash.el

 どのパッケージがきっかけでインストールされたのか、わからないけれど、「dash.el」がインストールされている。

;;; dash.el --- A modern list library for Emacs

 だそうだ。
 「-flatten」というのがあってお気に入り。

(-flatten '((1 2 3)(4 5 6)))
(1 2 3 4 5 6)

 で、素の ABCLを使っていて「flatten」が必要になった。
 「alexandria」をインストールすれば、いいんだろうが、諸事情というものがある。
 「dash.el」の「-flatten」が使えないもんだろうか。
 「–map」「–mapcat」「-mapcat」「-flatten」を喰わせてみたところ。

(-flatten '((1 2 3)(4 5 6)))
(1 2 3 4 5 6)

 動いた。

2020年1月22日水曜日

loopマクロ

 たとえば、あるlistの中から奇数だけを抽出したい、というとき。

wrk
(1 2 3 4 5 6 7 8 9 10)
(loop for x in wrk
      collect
      (when (oddp x)
        x))
(1 nil 3 nil 5 nil 7 nil 9 nil)

 こうやると、nilがまじってしまう。このケースだと、remove-ifを使えば、いいのだけの話なのだけど——loopマクロでこんな風にしていた。

(loop for x in wrk
      append
      (when (oddp x)
        (list x)))
(1 3 5 7 9)

 なんかいまいちだなぁ。
 なんとこうできるのだった。

(loop for x in wrk
      when (oddp x)
        collect x)
(1 3 5 7 9)

 すげえな、loopマクロ。

2019年9月23日月曜日

CommonLispでファイル検索

 たとえば、ホームディレクトリの下の「.txt」ファイル。

(UIOP:DIRECTORY-FILES (UIOP/PATHNAME:WILDEN "~/") "*.txt")

2019年7月20日土曜日

Maximaに裏から入る

 MaximaからLispのREPLへ移ることはできるけれど

(%i68) to_lisp();

Type (to-maxima) to restart, ($quit) to quit Maxima.

MAXIMA> 

 これだと、モードは「Inferior Maxima mode」のままなのでかなり不自由。
 やはりLispならslimeからだよね。
 というわけでMaximaでswankを動かす。

:lisp (load "パス名/swank-loader.lisp" :verbose t)
:lisp (swank-loader:init)
:lisp (swank::create-server :port 14005 :style :spawn :dont-close t)

 あとはポート14005番に「slime-connect」で接続すれば、Maximaを動かしつつ、裏からLispでいじることができる。

(%i7) wrk:444;
(%o7)                                 444

 なんてやって

MAXIMA> $wrk
444
MAXIMA> (setq $wrk 678)
678
MAXIMA> 

 見て変更して

(%i8) wrk;
(%o8)                                 678

 なんてことができる。だからどうした、という話だけれど。
 でもきっとこれで、ここ(Lisp)からgnuplotを使えるようになるんだよなぁ。

2019年6月29日土曜日

SBCLをバージョンアップ

 roswellを使ってMacBook AirのSBCLをバージョンアップした。

ros install sbcl/1.5.3
CL-USER> (lisp-implementation-type)
"SBCL"
CL-USER> (lisp-implementation-version)
"1.5.3"

 しなくてもいいかな、と思っていたのだけど、関数へjumpする「slime-edit-definition」で微妙にソースの場所がずれる——最新版にすれば、だいじょうぶじゃね?
 正解だった。

2019年6月21日金曜日

Excel-grep

 まぁ、やはり一番、よく使うのはgrepなわけですよ。
 テキストファイルならそれでいいんだけど、Excelファイルががっつりあったりすると泣けてくる。
 Windowsのエクスプローラーから検索できるんだけど、なんか使い方がよくわからないのでストレス。だったらjavaのPOIでExcelの中身を見れるんだから——ABCLで取りこめばいいんじゃね?
 で、つくってみる。

 あとはslime経由でEmacsにデータを取りこんでごにょごにょする、と。

 ちょっと「jinput-stream」をcloseしてないのが気になるけど、ま、いいか。

2019年5月18日土曜日

コアダンプ

 コアダンプというと、やはりUNIX系の感覚があるので嫌な感じを覚えてしまう。けれど、CommonLispだとまた、ちがうらしい。コアダンプを使うと、起動が速くなる、と。
 まさか。
 faslを読みこむのとそんなかわらないのでは?
 Raspberry PiのFreeBSDのCLISPは起動はABCLほどではないけど、やはり時間がかかる。1、2分? プログラムのloadをあわせたらもっとだ。ダンプしたら速くなるのか?

(ext:saveinitmem "ほげほげ")

 プログラムをloadした状態をdumpして。

clisp -M ほげほげ

 で、起動。
 驚いた。
 一瞬だった。
 しかもdumpした状態から作業できる1。
 すげえ——でも別に実行が速くなるわけではないのだった2。

Footnotes:

1

もっともslimeとの接続はうまくできなかった。

2

同じことをMacのSBCLでやろうとしたけど、dumpできなかった。どうもthreadがあるとだめらしい。

2019年5月17日金曜日

FreeBSD12 on RaspberrPi 3 Model B

 いくつかメモ

  1. FreeBSD12はimageをまちがわなければ、RaspberryPiで動く。
  2. しかも64bit対応。
  3. ただし、オンボードのWifiは認識しないので有線LANが必要。
  4. pkgはそろっている(Emacs、PostgreSQLなど)。
  5. CommonLisp系はABCLのみ(つまりjavaは動く)。
  6. ただしportからCLISPがインストール可能(Threadはまだ未対応)。
    そのときはgccをあらかじめ、pkgからインストールしておくこと。
  7. ntpを設定しておかないと時間は狂いっぱなし。
  8. swapは設定されていないので設定する。
  9. CPUの温度の取得は「/sbin/sysctl dev.cpu.0.temperature」

2019年5月16日木曜日

CLISP on RaspberryPi

 ABCLがあまりに激遅だったので、CLISPで発生したコンパイルエラーを追うことにした。
 これは真面目に見れば、すぐにわかるようなたぐいのものでたぶん、バージョンのちがいに起因するものなのだろう。簡単に直せた。
 これでようやくRaspberryPi上でCommonLispが動く1。
 ただしThreadは未対応——これはThread対応でコンパイルをかけると、エラーになるからで、すこし追ってみたけれど、よくわからず。どうもARM64をまだサポートしていないだけのように見えるけど——わからん。

2019年5月15日水曜日

ABCL on RaspberryPi

 CLISP1上で自分の作成したプログラムを動かそうとしてみたら使っているライブラリの中でコンパイルエラーになった。あ、あかんのか。調べてみるのも面倒だし、別のCommonLispをインストールした。ABCL2。これならjava上で動くから動くだろう。
 ところがこれがむちゃくちゃ遅かった。
 噂で馬鹿っ遅いということは聞いていたのだけど、普通に使えていたのでだいじょうぶだと思っていた。
 これはパソコンが速かっただけらしくてRaspberryPiでは耐え切れるレベルをふり切っていた。
 slimeの初動で、あまりに立ち上がらないので3ひと晩、寝てしまったほどだ。
 翌朝、さすがに立ち上がっていたのだけど、調べてみると、約4時間半かかっていた。
 これはあれだよね。
 初だから裏でビルドしているからだよね。
 だから二回目は速いはず。
 ……10分経過……トイレにでも行ってくるか……まだか……20分……ここまで遅いと楽しくなってくる……おっ、あとはslimeとのconnectか…… ん?…… まだ?…… まだなの?……ふぅ……やっとつながった。
 ——使えん4。

 でもThreadは使えるんだよなぁ5。

Footnotes:

1

pkgにはなかったけれど、portコレクションにはあったのでビルドした。SBCLはだめだった。

===>  sbcl-1.5.0,1 is only for amd64 i386, while you are running aarch64.
2

CMUCLも、SBCLもインストールできなかった。SBCLなどソースをもってきてコンパイルまで試したのに。

3

横でtopコマンドで動きを見てなかったらCtrl-Cを連打していたレベル。

4

どこまで遅いのか、自前のプログラムをloadしてみていたらEmacsが落ちた。な〜ぜ〜。

5

でも某ライブラリでコンパイルエラー。あまりに遅いので追う気力がわいてこない……。

2019年5月9日木曜日

HyperSpecをFreeBSDで

 そういえば 「HyperSpec」もpkgにあったので。

sudo pkg install clisp-hyperspec-7.0

 で、インストール。
 インストール先は

pkg list clisp-hyperspec-7.0

 で、確認してemacsのinit.elに定義した。

(setq common-lisp-hyperspec-root "file:/usr/local/share/doc/clisp-hyperspec/HyperSpec/")

 ふむ。だじょうぶそうだ。

2019年5月6日月曜日

Threadプログラミングはむずかしい

 Threadごとにconnectionを管理できるようにしたからだいじょうだと思っていた。たしかにThread二つまでは何ともなかった。それを四つにしたらおかしくなった。
 いきなりPREPAREがすでに使われている、とエラーになる。
 ——?
 どうして二つで動いていたものが、四つだと動かなくなる?
 しかもすぐに起きることもあれば、しばらくたってから起きることもある。同じ処理をくりかえしているにもかかわらず。
 三日、考えこんだ。
 使っているライブラリも疑った。
 どうデバックすれば、いいかも思いつかない。タイミングで発生しているのはあきらかで——それを補足するのはどうすれば、いいのだろう。ソース百遍。
 三日目にしてようやく気づいた。
 threadごとに管理しているconnectionはハッシュテーブルを使っている。
 同時にこのハッシュテーブルにアクセスされたらどうなるんだろう?
 あっ、まずいかもしれない。
 ハッシュテーブルがthreadセーフなら別だが——。
 どうやれば、それがわかるのか、わからなかったのでとりあえず対処した。
 「with-lock-held」で処理を排他1。
 それでエラーはいちおう起きなくなったように見えた。が、それは頻度が極端に減っただけで起きるときには起きる。あれ?
 これがわからない。謎だ。
 同じPREPAREがすでに使われているというエラーなのだが——たぶんthreadセーフじゃないところがまだ、どこかに残っているのだろう。あるいは使っているライブラリかもしれない。むずかしい。
 これを避ける方法にはsqlを発行しているところをハッシュテーブルのときのように排他処理をかければ、いいのだが……それだと並列処理の意味がなくなってしまう。
 threadひとつだけの場合とかわらないからだ。
 まったくthreadで動くようにしたらthreadにした意味自体がなくなってしまう、という……。
 なんて厄介な2。

Footnotes:

1

中身はMUTEXを使っていた。

2

最終的にはエラーが起きているPREPAREを生成している関数だけを「with-lock-held」で整流化してなんとかなった。今のところ、エラーは起きていない。ただしそこで待ちがはいるため、CPUの使用率は全体として80%をこえなくなった。それでもthread一個並みになるより全然ましだけど。

2019年5月4日土曜日

ASDF on FreeBSD

 SBCLは使えるようになったのだけど、立ち上げるときにWarningがでているのが気になってしかったなかった。しかもどうもASDFがらみ。
 英語なのでわかりませ〜ん。
 とばかりいってもいられないのでGoogle翻訳の片言日本語で読んでみた。

 なんか、ASDFがインストールされているけど、そっちは使わないよ、古かったりするからね、管理者権限があるなら削除した方がいいよ、ちなみに「~/.config/common-lisp/source-registry.conf 」は使えないよ……。

 って書いているような気がする。
 なんか、状況は一致するな。
 でもそもそもASDFを入れた覚えはないんだけど?
 ところが、調べてみたらインストールされていた。どうやらSBCLをインストールしたとき、いっしょに入ったらしい。その証拠に「pkg-delete」しようとしたら「SBCL」までいっしょに削除しようとする。
 おいおい。

 まぁ、実害はなさそうだ。
 いちおうpkgで入ったASDFをいじって見えなくしたらWarningはでなくなったし。解釈はまちがいなさそうだ。Warningは無視する方向にしよう。

 もしかしたらSBCLは独自のPATH構成にしているのかもしれない。それでSBCL対応のパッケージがいちいち、pkgに用意されているのかも。

2019年5月3日金曜日

FreeBSDでCommonLisp

 果たしてroswellにたよらずにやっていけるだろうか。
 なにはともあれ今まで何度も読み返していた「require, ASDF, quicklispを正しく使う」をふたたび、読み返す。いまいち、理解していないんだよなぁ、このあたりの話。roswellにたよってしまっていたのでなおのこと。
 とりあえず、FreeBSD環境にSBCLをインストールした。

sudo pkg install sbcl

 pkgにはほかにも「alexandria」とか、「asdf」とか、もろもろの他、SBCLのパッチがあたっているとおぼしき、バージョンもある。これを使うべきか?
 迷いつつ、SBCLをslimeで使えるように設定して。

(setq inferior-lisp-program "/usr/local/bin/sbcl --noinform")

 立ち上げてみたら「asdf」なんたらの文字が見えた。
 そうか。SBCLの中にasdfが内蔵されているのか。そういえば、ABCLもそうだった。それならpkgでASDFをインストールすることもないか。
 ところがいくらやってみても「~/.config/common-lisp/source-registry.conf 」に定義した内容がcommonlispに反映されない。試行錯誤すること数時間。
 あかんわー。
 自分のミスとは思えない。もしかしたらSBCL内蔵のASDFは「~/.config/common-lisp/source-registry.conf 」は無効になっているのかもしれない。じゃ、どうやって設定すれば、いいんだ?
 「quicklisp1」でもってきたライブラリの場所を認識させたいんだけど2?
 つらつら考えて「~/.sbclrc」に設定した。

(asdf::initialize-source-registry
        '(:source-registry
          (:tree "~/quicklisp/dists/") :INHERIT-CONFIGURATION))

 「asdf:find-system」で設定が有効になっていることを確認。
 よし。
 でもREPLで「ql:quickload」が使えないのは不便なので「~/.sbclrc」にさらに設定を追加した。

(load #P"~/quicklisp/setup.lisp")

 あれ、これでroswellからのREPLとほぼ、同じになったんじゃね?
 すくなくともぼくが使うかぎりにおいて。

Footnotes:

1

「quicklisp」はpkgになかったのでhttps://www.quicklisp.org/beta/からもってきて自前でインストール。

2

「~/common-lisp」の下は認識されているから自前のLispはここへ置けば、いいんだけど。