星田さんの記事に対するコメント。
> 2022/10/19
二分木探索のためにバリアント型うんぬん、というところ。うーんw なんか他の言語では存在しないみたいなんだけど、要するにn択の選択をさせてMatchで分けて処理をさせるという事かな・・レコード型では再現できない気がする
うん、実は結論から言うとレコード型で構わないんだ。
つまり与題は、Gaucheなら次のようにして書いて構わない。
こんな風にして書いて良いのなら、じゃあヴァリアント型、とは一体何なのか。
ここで次の記事を思い出してみて欲しいんだけど、もう一度概要をまとめてみよう。
ここで、性的静的型付け言語の雄、C言語で見てみる(※1)。
例えば次のようなバカみたいな関数を書いてみよう。
これはコンパイルしようとするとエラーになる。
実の事を言うと、C言語は「弱い性的静的型付け」言語の為、「強い性的静的型付け」言語のOCaml程煩くはないんだけど、それでも「ある決まった型の引数を受け取るように設計した」以上、原則、その「ある決まった型のデータ」を与えないとエラーを起こす(確率が高い)。
LispやPythonみたいな動的型付け言語のように、
;; Lisp(Scheme)
(define (foo arg)
arg)
;; Pythondef foo(arg):
return arg
と書いて「どんな型のデータだろうと引数として受け入れる」ような関数は書けない、って事だ。
しかし、プログラミングに於いて、「色んな型のデータを受け入れる」必要が全く出ない、ってこたぁねぇだろう。そして「型」に合わせて処理を変えたい、って思う事もある筈だ。
そこで、OCamlでは、性的静的型付け言語の縛りの中で、「どんな型でも受け入れられる」関数は書けないけど、ある限定した型のセレクションなら、それを1つの型として受け入れられる関数の書き方を発明した。
別の解釈では、特定の型の集合に対して、それらをまとめてなお、「単一の型名」を与える仕組みを開発した。
言っちゃえばそれがヴァリアント型、なんだよ。ヴァリアント型はある有限個の型をまとめて単一の型として定義する。このトリックのお陰で、ヴァリアント型を受け取る関数はその中で、ヴァリアント型に含まれる別の型に対して特定の演算を実行出来るわけだ。
そしてだからこそ、仮にOCamlユーザーがC言語ユーザーに
「OCamlにはヴァリアント、って型があるんだぜ?」
って自慢すれば、貧弱なC言語のユーザーは「そりゃ凄い」って感心するだろう。
一方、OCamlユーザーがLispやPythonユーザーにヴァリアント型を説明すれば
「どんな型でも受け取れる関数なんて当たり前じゃん?何がそんなに凄いのやら。」
って反応になるだろう。
そう、ヴァリアント型、ってのは、静的型付け言語ユーザーにとってはある意味福音なんだけど、動的型付け言語ユーザーにとっては「だから何?」って程度のシロモノでしかないんだよ。
従って、ヴァリアント絡みのOCamlの型作りは、Schemeの場合は構造体/レコード型の作成で代用出来る。
そしてSchemeは「どんな型でも受け入れる」関数を作れる以上、ヴァリアント型の価値は全く無いんだ。
従って、額面通り受け取るなら、次のOCamlのコード
もSchemeでは以下のように書くといい。
もう一度整理しておこう。
例えばOCamlでヴァリアント型として次のように型が定義されてたとする。
この場合、
- 大枠のjikoku_tと言う型は無視する。何故なら、これは複数の型を単一の型として纏める仕組み、であり、静的型付け言語の関数の引数の要請に拠るもので、動的型付け言語では無用の存在だから、だ。
- 方針としてはこの例だと、Gozen、Gogo、Noon、Midnightの全てをバラバラにレコード型として作るだけ、で良い。
つまり、例えばGaucheならこう書いちゃう。
こうしておけば、ヴァリアント型の実行例とも一致する。
OCaml:
Scheme(Gauche):
そして、OCamlの次のような関数を翻訳するとする。
動的型付け言語では引数の型がどうだろうと全く関係ないんで、結果全体的には次のようなコードになるだろう。
結果、OCamlでの次のような実行例は、
Scheme(Gauche)でも完璧に再現出来る。
ドヘーッ!!またお手間を取らせてしまった・・しかも内容が今の僕には高度すぎてすぐには活用出来ないかな(^_^;) ブックマークしておいてじっくり試してみます。分解して飛ばさず学習したらいつかは使えるようになるとは思います!
しかし普段使いの環境でもないのにすいません。
いや、全然構わないです。
っつーかホントGaucheが想定外だった(笑)。
割にスタンダード中のスタンダードを目指してるのかな、とか思ってたし、対Perlを尽く口にしてたようなトコあるんで、もっと気楽なスクリプト系言語処理系だと想像してたんだけど、実際は違った、と(笑)。
まさかmakeでコードをコンパイルする前提だ、とか夢にも思わんかったわ、と(笑)。
つまり、処理系として見てみると、GaucheはPerl/Python/RubyやRacketと同じラインにはいない。
いずれにせよ、折り目正しく使わなきゃなんねぇな、と(笑)。ちと気楽には弄れない。
ええっ!?これ不思議ですね・・transparentってただ値を見えるようにしてくれてるだけだと思ってたのに・・
多分、#:transparentで生成された文字列をstring=?で比較してんじゃねぇのかな。
表示が一致するなら中身も同じだろ、みたいな(笑)。
これが一番簡易なやり方、って言えばそうだと思う。
これなんて特に高度過ぎて・・とにかくGaucheでは構造体の比較は鬼門だってのを教えてもらっただけでも謎の落とし穴にハマる危険が減ってるんで大助かりです
ここ、二点ぐらい問題があるのね。
いずれにせよ、少なくとも、Gaucheはプログラミング初心者には優しくない。
10数年以上前?自分のWebページに掲示板設置したい、って人たちが大量にPerlに流れ込んできて、素人ながらにPerlに触れて、Perlを使いこなすようになっていった、って言うようなトコにはGaucheはいない。
結果、もっと「本格的な」プログラミング言語処理系です。
んで、例えばポール・グレアムはこう言ってんだけど。
個人的には、オブジェクト指向抽象化が必要だと思ったことは一度もない。 Common Lispは恐ろしいほど強力なオブジェクトシステムを持っているが、 私は一度もそれを使ったことがないんだ。ハッシュテーブルにクロージャを詰め込む とか、弱い言語だったらオブジェクト指向テクニックが必要だっただろうと 思えることはたくさんやってきたけれど、CLOSを使う必要に迫られたことは無かった。
一方、恐らく、川合史朗さんは、こういうカンジで自然とオブジェクト指向を前面に出してる辺り、ポール・グレアムとは違ってANSI Common LispのCLOS(Common Lisp Object System:※2)バリバリの人なんでしょ。
っつーかCGやってたらしいんで、さもありなん、って思う(※3)。
ぶっちゃけた話、例えば、
ってなってた場合、これに限定した等価比較述語を作る事自体は簡単ではあるんだ。
- 2つのオブジェクトが同じ型である事。
- オブジェクトの各スロットが同値である事。
つまり、
とでも書いておけばいい。
実際、
だしな。
ただ、メンドくせぇんだよ(笑)。プログラミングに於いてメンドくせぇは悪、の法則だとこれ、単に書きたくねぇんだよな(笑)。
実は熟練Schemerだと、何でもDIYしてた歴史が長いせいか、気にならんのかもしれんが。
熟練Schemerの方々(違
俺は嫌だ(笑)。
ちなみに、基本的には、その高度過ぎての部分は、オブジェクト指向で書かれてる事を除けば、上のfoo=?と全く同じ事をやってます(※4)。
だから結果、嫌だなぁ、って思いながらDIYしたのと同じ事になってます。
まぁでも、ホンマ、たまたまフラッとLispの世界にやってきて、Gaucheに触れたら結構困った事になるんちゃうか、とかマジで思いました。マル。
気分転換プログラミングと言えば「いつか甥っ子に仕込みたい」と狙っているScratch。
Linux版がこれ。バージョンも未だに1.x台らしいんだけど、それよりもこのフォントの汚さはなんなの(^_^;) これはやる気が奪われる
多分、Linuxだと、XWindowに近い低レイヤーのGUIの機能使って作ってんじゃねぇのかな。
たまにこういう「汚い」見た目のソフトウェアにLinuxでは遭遇する(笑)。
ちなみに、Scratchって最初はローカル用のフツーのプログラミング言語だったんだけど、3.0からはWebアプリになっちゃったのね。
2.0はどこに消えたんだか良く知らん(笑)。
まぁ、いずれにせよ、機能的にはホンマ、「Visual」Basicだよな(笑)。
いや、Microsoftの商標、って意味じゃなくって。
MITが作ったとは思えない程、関数型の欠片もありません(笑*※5)。
Win版とWeb版はこんな感じで美しくて思わず試してみたくなりますねぇ。PC6001で思い出に残ってる「万引少年ゲーム」「反射衛星砲ゲーム」なんかはコレで作ってみたいと思ってるんですよねぇ
ちなみに、今、isamさんの方ではScratchにかかりっきりです。
なんか、孫に教えたい、とか書いてなかったっけ。
結果、今、isamさんはScratchの専門家みてぇになってます(笑)。
これ!これですね、先月たまたまその子のお母さんと会話になりまして話題がプログラミングに及んだので
「いや〜絶対ウケると思うんですよ〜。リスプってのをやってるって言っておいてもらえます?」
とお願いしたんですけどリアクションは無いですねぇ。ちなみにその子はC#メインだったそうですけど今度Pythonもやろうとしてるらしいです(そういう話をお母さんにもするんですね)。機会があったらちゃんとリスト内包表記使ってるかチェックしたろうと思いますw
あ、ひょっとしたらその子、Lisp知らんのかもしんない。
若い女の子だから可能性はあるよなぁ。C#やってて、次にPython、ってトコ見ても「陽の当たるメジャー街道」を突き進んできたのかもしれんし。
良かったね、星田さん、潜在的には勝ったかもしれん(笑)。
陽の当たらない路地裏の怖さを教えてやれ(笑)。
って一体何の話だ(笑)。
ついに僕もgitを使うときが来たか・・と思いました。けどCametanさんの予想通りGit-hubの事だと思ってましたけど。現状、僕のバージョン管理はテキストエディタにコピペとCtrl+z連打ですからね・・w
うん、git導入するには結構いいタイミングなんじゃねぇかなぁ・・・。
一応、大雑把にヴァージョン管理システムの仕組みを。
ザックリ言っちゃうと、セーブポイントを作るシステムなの。
例えばプログラムを書いてて、上手く動いたんだけど、なんかもうちょっとソースコードを修正してぇな、とかなった場合。
今「上手く動いてる」プログラムをデータベース、つまりヴァージョン管理システムだよな、に登録しておく。そしてプログラムを修正するわけ。
ところが、修正が上手く行くとは限らないワケじゃん?やべ、失敗した!とかなった時、プログラムファイルを消して覚えてる限り元に戻すように書き換えて・・・とかやんないでいい。ヴァージョン管理システムで、セーブポイントに「巻き戻す」と、あら不思議、修正する前のソースコードに戻ってます・・・とか言うカンジのツールなのね。
要するに、ファイルのセーブをもっと効率的に行う補助ツール、って考えて良い。
んで、コマンドラインで解説されてる例が多いんだけど、例えばWindowsでのTortoiseGitとか、マウスの右クリックにコマンド仕込んでくれたりするんで、意外と、いわゆる「解説書で書かれているクソマジメなCLIによる使い方」なんかより遥かにラクに使えるワケよ。右クリックして選択、だけで良かったりするし。
まぁ、概念的なモノとか、「具体的な使い方」をWebサイトとかあるいは書籍で学ぶ価値はあるけど、到達地点そのものはそこまで敷居が高いワケじゃないです。右クリックでO.K.なんでね。
> 2022/10/20
あ!そうなんですね!alist-cons alist-deleteってなんか破壊的変更なんだろうなと思ってました。
一応、命名規約的には「破壊的変更をする」関数名には"!"を末尾に付ける、って事になってるんで、"!"がケツに付いてない関数は破壊的変更をしない、って考えて良いです。
※1: プログラミング学習再開から1年経った事だし、凄いアビリティ上昇率なんで、ここからは場合によっては積極的にC言語のコードを紹介していく(かもしんない)。
「C言語を勉強するように」と言ってるんじゃなくって、「ある程度読めるようにしておこう」って事だ。
そして、実の事を言えば、「一回も触った事が無い」プログラミング言語のコードを「ある程度いつの間にか読めるようになってる」ってのがプログラミング慣れへのバロメータでもあるんだ。
そしてその判断基準に使える「外国語」としては構文はともかくとして、C言語が意外と向いている。これもC言語が基礎だから、と言った理由ではなくって、単にC言語はLispの視点から見るとあまりにもお粗末な機能しか無いから飛び道具使用率が他の言語に比べると全くと言って良い程無いから、なんだ。
要するに、何らかのスーパーな機能があって、それを使われると解読がムズくなるんだけど、C言語はショボいんでそういう心配がほとんど無いわけだよ(笑)。まぁ、仮に機能がショボい事を基礎と呼ぶんなら、確かにC言語は基礎だ(笑)。
反面、例えばC言語系のJavaなんかを今の時点で「読め」と言われるとまだ苦労するだろう。何故ならアイツはオブジェクト指向言語なんで、コードを読む際にもその「オブジェクト指向と言う機能を使った記述」がノイズになって、流れが掴めないんだ。
従って、Python、Lisp、OCamlと学んできた星田さんなら、「関数の書き方」を理解してる以上、C言語での「関数」も意味は分かると思う。食わず嫌いをせず、読んでみて欲しい。「外国語」のC言語だけど、たまにはロクな機能がない、事も役に立つ、ってな話だ(笑)。
そして「書けるようになれ」って言ってるワケじゃなくって、あくまでも「読めるようになれ」って事だよな。
ちなみに、本当の自然言語での外国語の上達法で、「日記を書け」とか言われるのも、一般に書く方が読むより難しいから、だ。逆に言うと、常に「読む」方が「書く」より簡単だ。英語のエロ小説を読めても英語でエロ小説を書く方が遥かにムズい、って事はある種想像可能だろう。
※2: 詳細は実用Common Lisp(PAIP)の13章を参照の事。
※3: 実はCommon Lispは、80年代後半辺りはCG研究の最先端にいて、その必要性もあってCLOSが作られた、と言う側面がある。
ポール・グレアムは「生まれ変わってもう一度大学でプログラミングを学ぶならCGをやってみたい」とどっかで書いてたような気がするんで、実は彼はCGには明るくない。
結果、「ポール・グレアムがCLOSを使わないで済んだ」と言うのは、「単にばか」と謙遜染みた事を言ってるが、単純に当時の最先端のCG研究に関わってなかっただけ、と言う見方が出来る(人工知能の方に行ってたらしい)。
反面、川合史朗さんは死ぬほどCGやってたんだろう。往年のスクエアだし(笑)。
※4: これも何度か言ってるが、実はCLOSのシステムは基本的に、大域的にデータテーブルを用意しておいて、そこに関数なりラムダ式を追加する事によって「メソッド」を実現している。
これを総称関数方式と呼び、C++/Java/Python等のメジャーなオブジェクト指向とは趣が違う。
この記事を参考にして欲しい。
※5: ちなみに、Scratchと言うプログラミング言語は、MITメディアラボ、と言う大学の研究機関が中心になって開発が始まった、と記憶してるんだけど、かつて、ここに大量の寄付を行ったのがご存知任天堂だ。