星田さんの記事に対するコメント。
>> 2023/02/18
あ、なるほど!すごくシックリ来ました。結局C言語も高級言語なのでガワの中身に直接コンタクトしてるわけでは無いって事ですかねぇ
うん、端的に言うとそういう事です。
なのに、ここでも批判したけど、いまだに「箱の説明」とかやってんのね(笑)。
箱で説明したから、ってコンピュータの動作が分かる、とか言うのとは関係ないじゃない(笑)。メモリをキチンと説明してるわけでもねぇし。
むしろ逆に、「変数」(variable)って数学用語を何故使ってるのか、って意図を丸々潰してる。数学用語を持ち込んでる最大の理由は「概念の抽象化」なわけでしょう。「数学で言う変数と同じなんだよ」ってのを言外に言ってるわけ。
そういう「思考の抽象化」を無駄にして「箱」っていまだ言ってたりするから「バッカじゃねぇの?」とか思ってる(笑)。
こんな説明ってクソの役にも立たない。
百歩譲ったとしても、これで「コンピュータの動作が分かった!」とするなら、別にそれってC言語のお陰でも何でもないわけでしょ(笑)。どのプログラミング言語にせよ同じ効果が見込める筈だ。
つまり、こういう説明は無駄だし、C言語自体にも「コンピュータの動作原理が分かる」ような教育効果なんざねぇ、ってのが結論にならざるを得ないわけ。
この辺が「2000年に渡る」伝統がある数学教育と「100年の歴史もない」プログラミング教育と決定的に違う辺りなんだ。
プログラミング教育って「何をどうやって教えるべきか」ってのがまだ確立されてない分野なんだな。
例えば、本当に「C言語がプログラミングの基礎」とか言うのなら、マジでいきなり「アセンブリコード」を読んだ時点で、ある程度「何がどうなってるのか」分からないとならないんだよ。ちょっとの学習で「アセンブリ」や「機械語」がスラスラ読めて理解出来なきゃならない筈だ。
でもんな事ないわけでしょ?C言語学ぼうと学ばまいと、ある程度の「分厚い」専門書を読まないとアセンブリのコードとか読めないんだよ。じゃないと「アセンブリ入門」なんて本が出る筈ない。
星田さんに以前言ったけど、今かなりLisp慣れてきてて、「読む分にはC言語やPythonやJavaScriptのコード」を全部理解出来ないとしても「流れが分かるようになってる筈」って言うレベルにさえ到達しない筈だ。
そういう意味ではC言語と機械語/アセンブリ言語って、いくらCが「低レベル」でもやっぱ差があるのね。
つまり、ここでも「C言語が基礎」ってのは全く意味が無い戯言だと言う事が分かる。
んで、歴史的に見ると、おそらく「コンピュータの動作が分かる」ようになる高級言語って、PCに搭載されてた「構造化されてないBASIC」の方が効果が高かったんじゃねぇのかなぁ。
つまり、黎明期のPCで、ゲームを書く際に「スピードを上げたい」って場合、使い慣れたBASICじゃなくって人々はアセンブリや機械語に入っていかざるを得なかったわけでしょ。
で、実際に入っていった人が多数だったわけだ。
なんで当時の人がアセンブリや機械語に行こう、って思えたのか、っつーと、結局「構造化されてないBASICの書式」と「アセンブリ/機械語の書式」ってのが、両者とも言わばバッチ式(逐次実行を主としたプログラム)だったから「似てた」ってのはあったと思うんだよね。
BASICで一行で済むトコがアセンブリ/機械語だと20行以上必要だったかもしんない。でも「アレして、次コレして・・・」って記法は両者とも同じだったんで、行数が増えようと「形式」自体は全く変わんなかったわけ。
従ってBASICを「よく分かってた」人はアセンブリ/機械語にそこまで抵抗感じなかったと思う・・・まぁ、ニーモニック覚える手間はあるけどさ。
そして「コンピュータは原理的にはインタプリタだ」って原則に忠実な結果が出た筈だ。どっちも一行一行見ていって随時処理していく、って形式は同じだったし、しかも当時のPC用BASICだと「ジャンプする」ってのも当たり前だったんで、同じ事をアセンブリ/機械語でやろうとするのも、そこまで「意識のズレ」ってのは生じなかったと思うんだよ。
本当に「コンピュータの動作原理」を高級言語でシミュレートする、ってぇのなら、いまだにN-88 BASICみたいな「構造化されていない」BASICの方が教材としてはC言語より遥かにマシなんじゃねぇの、って思ってる。
実際、たくさんのアセンブリや機械語書けるヤツを生み出してきた「実績」があるわけだしな。
ちなみに、亡くなって久しいんだけど、日本のかつての有名なLisperに、慶應義塾大学の中西正和センセ、って人がいたのね。
この人がいた時の慶應義塾大学のプログラミングの授業は凄かったらしい。どこぞに書いてたんだけど、この人がやってたカリキュラムだと、慶應義塾大学では「アセンブリ言語」と「Lisp」のたった二種類しか教えなかったそうだ。
曰く、
「一番低レベルのプログラミング言語と、一番高抽象度なプログラミング言語の2つさえ知っておけば、間の言語なんてどーにでもなるでしょ?」
との事で(笑)。
いや、こういうパースペクティヴを持ってる人があんまいない、って事がプログラミング教育をわやくちゃで「戯言ばっか」の状況にしてんだ、とか思ってる。
ガツン!と来ましたねぇ!あ、そういう事か〜(←間違いなくまだ分かってないw)と。なんとなく段々と理解の解像度が上がってきてる気がする・・これは無理やりにでも使ってみなければ!ありがとうございます(^o^)
うん、色々使って実験して覚えてください。
そういう「実験が出来る」とか、一見、他の言語から見ると「飛び道具的な関数の作り方/使い方」を学べるのがLispを学ぶ一番良いトコなんで・・・。
C言語脳がPythonを使って教える、とか言う環境では決して得られないモノがLispの伝統の中にはしっかりとあるのよ(笑)。別に僕が思いついて、僕がエラい、とか言うんじゃなくって(笑)、「Lispを学んだ人」には同じような事を「思いつく」しっかりしたバックグラウンドが出来るんだ。
件のコードは例えばこんな風にmapとfoldrを組み合わせてもいいだろうし。
(define (place-world w)
(foldr (lambda (fun init)
(fun init))
*window*
(map (lambda (fun arg)
; クロージャを作成する
(lambda (x)
(apply fun `(,@arg ,x))))
;; 関数のリスト
`(,place-branches ,place-message ,message-area
,place-characters ,place-back)
;; 関数の引数のリスト
`((,(world-branches w) ,(world-color w))
(,(world-message w)) ()
(,(world-characters w)) (,(world-back w))))))
いずれにせよ、Lispって「学んだ事はそのまま応用して/使っても構わない」言語で、実はこういうプログラミング言語って少ないと思う。
大体のケースだと、特に仕様がない言語なんかでは「✕✕って出来る」って聞いても「実装上の理由でおかしな結果になる」とかあるわけよ(笑)。
Lispの場合はそういう事がまずない。「学んだ事がそのまま使える」って事は「理屈さえ合ってればキチンと動く」と言う事。いや、実際、「プログラミングは理論が・・・」とか言うけど、結構な確率でそういう言語って少ないんだわ。
そして「実装上の理由により」とか言うのって「理屈」じゃなくって「単なる言い訳」だったりするんだよな(笑)。そういう信頼度が低い事はLispではほぼ起きない。そしてそれで速度が低下します、とか言うペナルティも無いんだ。
安心して色々と実験してみて欲しい。
こういう話を聞くと脳の可能性はまだまだ未知数だ・・とワクワクしますねぇ!訓練でなんとかなるものならメソッドが知りたいですよねぇ・・腐るほど居たということは再現性があるわけだし。今からアセンブリはいらんかなぁ・・と思いますけど
そうね(笑)。
と言うか、今の時代それやっちゃうと、ポール・グレアム的な「関数型プログラミング」スタイルじゃなくなっちゃうよね(笑)。
いや、だから90年代入るまでに、実はLispって「関数型プログラミング言語」として生まれた割には「関数型プログラミングスタイル」自体はポピュラーじゃなかったんだよ。
「アセンブリをチューニング出来るスタイル」って事は言い換えればC言語/Pascal的な「手続き型言語スタイル」で書いてた人が多かったわけでさ。
それが現代的な意味で「望ましいLispプログラミングスタイルなのか」って言われると必ずしもそうじゃない、と思う。
ただし、「いざとなったら伝家の宝刀を抜ける」ってのはいまだANSI Common Lispの魅力だとは思います。
何にせよ「出来ない」と言われるより「出来る」方が良いわけだからさ。
そういう意味では、確かによく言われる通り、ANSI Common Lispは「理想的な関数型言語」ではなく、「現実的なエンジニアリング目的の」プログラミング言語なんです。
>> 2023/02/20
>>> 話題その2 DD&Dの実験など
さて、ここで「型により動作振り分けをしたい」って問題が出て来た。
んで、「そういう場面はよくある」んだわ。
このプログラムだけじゃない。
理論的な話をすると、前に星田さんが自力で思いついた「タグ付きデータ」が含有してた問題であり、そしてSICPで紹介されてた「データ主導プログラミング」と関係する問題だ。
いずれにせよ、「型により動作振り分けをしたい」って事はよくある。
よくある以上、これはユーティリティとしてマクロを作るべき局面だ。
ユーティリティとしてマクロを作っておけば、今後同種の問題が出て来た時に対処がラクになると思う。
describeライブラリを利用したマクロを設計すべきだ、と助言をしておこう。
んで、なんで「よくある」と言えるのか?っつーとANSI Common Lispならこれに対処するマクロがビルトインだからだ。ANSI Common Lispは巨大な(電話帳的な・笑)仕様だけど、「よく使う」ものは全て入ってる。
ズバリ、ANSI Common Lispだったらこういう時使うべきシンタックスはtypecaseだ。これが「型による処理を振り分ける」caseの特殊型、って事になる。
これをdescribeモジュールを利用し、マクロとして実装してユーティリティにしよう。
そうしておけば、今後似たような要求が出た時ハナクソで対処可能となる。