見出し画像

Retro-gaming and so on

RE: プログラミング日記(とか言ったりして)・随時追記 2021/10/19 & 2021/10/18

ええと例によって星田さんの記事に対するお話。
もう完全にLisperやねん(笑)!

> 2021/10/19

まず基本的な話をすると、発想、っつーか解答はほぼ完璧です。
紫藤さんの解は「再帰入門」的な解で、星田さんの解は基本「末尾再帰」な解答になってる。
従って、シンプル/シンプルじゃない、ではなく、そこにあるのは再帰/末尾再帰の対比です。
そして末尾再帰最適化、って意味だとテクニカルには星田さんの解が正しい。
当然、紫藤さんが「間違えてる」んじゃなくって、末尾再帰を導入する前の解になってるから、そうだ、ってだけです。

従って


ANSI Common Lispっぽいけど、もうここから正解。
何も悩まなくて良いです。
Schemeっぽく書きたいのならinternal defineにすれば良いだけ、です。


さて、ここでどうして形式の違いでANSI Common Lispっぽい、とかSchemeっぽいとか出てくるのか。

実はプログラミングでは「名前空間と言う考え方があります。あるプログラム内で同じ名前の変数とか関数とかを作ったらダメだ、って事なんですが。
例えばPythonだと、1ファイル1名前空間、と言うルールがある。別のファイルから関数を持ってくる場合、"別のファイル名.関数名"、ってカタチじゃないと呼び出せないようになっています(これが、Pythonのimportの仕組みです)。これで、自分の作った関数が別のファイルに定義された関数の名前と同名だったとしても衝突が回避出来る事になる。
ANSI Common Lispの場合、自在に名前空間を分割、利用出来る仕組みがあって、それをパッケージと呼んでいます。つまり、ガンガン名前空間を「作る」事が出来る、っちゅうこれまたトンでもない仕組みを採用してるんですよ(笑)。
と言う事は、バンバン大域的に関数を定義していっても構わん。何か関数名出し尽くして新しく名付けようとしたものがぶつかりそうになったらパッケージを分けちゃって新しく名前空間を定義しちまえばよい、と。それがANSI Common Lispの設計思想なんです。
だから再帰関数を一つ定義したい、とか言って補助関数をバンバン大域的に定義しても怖がらないわけです。名前空間が自在に作り出せる以上「名前の重複の可能性」なんざ心配に値しない。
反面、Schemeは仕様的に言うと、ANSI Common Lispみたいな「大雑把さを許す」名前空間の構造にはなってないです。
実際のトコ、実装によってはANSI Common Lispみたいな「パッケージ」を導入してるモノもあるんですが。
でもSchemeユーザーは「大域的に名前を汚す」って事をあまりしたがらない。
結果、補助関数を作成する時、ローカル関数として閉じ込めて、外部からアクセス出来ないようにするのを好むわけです。


これも「ほぼ」正しい。まぁ、reverse入れようか、って話はともかくとして。
ぶっちゃけ、星田さんは既にLispの真髄を分かってる。それは

if等の条件分岐は文ではなく式なのでどこにツッコんでも可

って辺り。そしてアキュムレータであるnlsに条件式ツッコんでる(笑)。
ここにフツーのプログラミング言語を学んできた人は到達出来ないんだ。
星田さん、滅茶苦茶良いセンスしてる。
うん、完全にLisper向きだわ(笑)。

新しい空リストにCONSで追加してゆけば・・と思ったけど空リストは()で入ってしまう

結局ね、ここだけ、なの。
要するにconsingせんでエエのよ(笑)。何もせんでnlsをそのまま返しちゃえばエエの。


ほら。consしなければ余計なカッコは入らないでしょ?
そう、「何もしたくない時」は「何もせんで」ええ、と言う事やね。

しかし僕は代入が好きなんだなぁ・・と。

いや、全然。星田さん代入してないよ。
Schemeで代入はset!なんで。set!してない限りビビらんで大丈夫です。
(Schemeだと破壊的変更を伴う関数には!を付ける、と言う命名規約がある)

ええとね、見た感じ、末尾再帰は全然問題ないと思う。
んで、Schemeだと通常、「末尾再帰を書けるか否か」ってのが境界線なのね。
テクニカルな話をすると、末尾再帰最適化って機能がある以上そうなるの。
だからもう大丈夫なんですよ。
フツーの再帰の出番は無いです。

そもそも、フツーの再帰の出番ってのはSRFI-41 使って遅延評価やらんと無いんじゃねぇかな・・・?
遅延リスト、ないしはストリーム相手の場合、末尾再帰で書くと無限ループに陥ったりすんのね(笑)。遅延評価だと引数の評価法則が変わるんで、引数丸ごと末尾再帰関数にすると上手いこと行かなかったりするわけ。
だからフツーの再帰を遅延評価では使うけど、逆に言うと遅延評価を使わない限り末尾再帰で大丈夫、っつーか、むしろ「末尾再帰を使いまくれ」ってのがSchemeのコツかしらん。

> 2021/10/18

あと、マンガでわかるLISPというのを発見して読む、マンガ部分が不要なような・・。

あはははwww
ちなみにそれ、作者はリリカル☆Lispの作者です(笑)。

「一通りザーッと読んどく」ようにアドバイスを受けた関数プログラミングの論文(?)を「いくらなんでも」ってくらいにザーッと読む。

うん、全然ザーッと、でいいですよ。「いくらなんでも」もクソもない。

なんつーんだろ。こういうのってブックマークしといてさ。
「一回精読しときゃいい」んじゃなくって「何度もザーッと読む」方が大事だと思ってんですよね。
なんせLispじゃない以上本懐じゃない。
ただ、たまに読めば良いアイディア、とかひらめきを与えてくれるかも、って事ですよね。
例えば。

(reduce f a)を理解する一つの方法は、リストのなかで、consが出現するとこ ろをすべてfで置換え、nilが出現するところをすべてaで置換える関数だと看倣 すことである。例としてリスト[1,2,3]を取ることしよう。このリストは 
  cons 1 (cons 2 (cons 3 nil))
ということなので、(reduce add 0)はこれを 
  add 1 (add 2 (add 3 0)) = 6
に変換する。そして、(reduce multiply 1)はこれを 
  multiply 1 (multiply 2 (multiply 3 1)) = 6
へ変換する。そうすると、(reduce cons nil)はリストを複写するものであるこ とは明白である。ひとつのリストの要素をもうひとつリストの前へconsしてい くことで、二つのリストを連結することができるので、 
  append a b = reduce cons b a
というのを見いだすことができる。例をあげれば、 
  append [1,2] [3,4] = reduce cons [3,4] [1,2]
 = (reduce cons [3,4]) (cons 1 (cons 2 nil))
 = cons 1 (cons 2 [3,4]))
 (replacing cons by cons and nil by [3,4])
 = [1,2,3,4]

これ何を書いてるか分かるでしょ?あれだけ悩まされたappendがreduce系の高階関数で簡単に書ける、って事を示唆してる


あの論文にはそのテのテクニックが割とガッシリ詰まってますね。

 夜、気力がちょっと回復したのでClispとXyzzyの導入と環境設定を行う。はぇ~・・Windows使い始めて27年、こういうの初めてやった。

うん、フツーはやらんのよね(笑)。
大体、このテの事柄ってDOS使ってました〜、とか言う人が嬉々としてやる(笑)。一般人はしない(笑)。
WindowsはそういうOSじゃない(笑)。

あとね、もうちょっとだけ、マシにしたい、って場合。
homeフォルダでってファイルを作る。
これも拡張子だけのファイルで、今度はxyzzyを初期化する為のファイルです。
それをメモ帳とかで開けて・・・まぁ、xyzzyで開けてもいいんだけど、いずれにせよ、次のコードを貼って保存する。

(setq *default-fileio-encoding* *encoding-utf8n*)
(set-default-directory "C:¥¥home¥¥")
(define-key *text-mode-map* #¥C-a 'selection-whole-buffer)
(dolist (modes '(         ; ここにモードを追加する
       ("¥¥.lisp$" . lisp-mode)
       
       ))
(pushnew modes *auto-mode-alist*))
(setq *popup-completion-list-default* :always)

そうすれば
  1. xyzzyのデフォルトエンコーディングはutf-8になる
  2. xyzzyのデフォルトディレクトリも"C:\home\"になる
  3. C-a(Ctrlキーとaの同時押し)で全選択になる
  4. 拡張子がlisp及びxyzzyだったらLispモードでファイルが開く
  5. 補完候補がポップアップするようになる
筈です。「もうちょっとだけ」便利になる筈(※)。


それで、xyzzyもちょっと特殊なEmacs系キーバインドなんで(例えば新規ファイル作成がWindowsでお馴染みのC-fじゃなくってC-x C-fになってたりする)、マウスに頼った方がマシだ、ってなるでしょうが、一応、キーバインドの表を作ってる人がいたんで、そのページを紹介しておきます。
印刷して手元にでも置いておけば良いでしょう。

※: ホンマ余談だが、xyzzyにはGNU Emacsのようなinferior-lisp-modeがない。探したがない。
inferior-lisp-modeがあったらもっと使いやすいのに・・・ってのが極めて残念、である。
結果、表層的にはxyzzyはGNU Emacsに近いが、使い方、と言った向きではどっちかっつーとvimの感触により近くなってる気がする。
  • Xでシェアする
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

最近の「RE: プログラミング日記」カテゴリーもっと見る

最近の記事
バックナンバー
人気記事