星田さんの記事に対するコメント。
> 2022/10/06
その他いろいろ擁護してもらったりして・・ありがとうございます!
いや、全然擁護してません。事実しか書いてない。
んで、別のトコにも書いたけど、そもそもプログラミングに慣れれば慣れる程エラーを喰らう回数は加速度的に増えていくんだ(笑)。プログラミングに慣れればエラーが減る、なんつー思い込みは幻想だ(笑)。
当然、プログラミングに慣れれば自分でプログラムを書きたくなる。作るプログラムは教科書の例示より複雑になる。そしてプログラムが複雑になればなるほど当然エラーを喰らう回数は増えるわな。
結局、プログラミングに慣れてる人とプログラミング初学者の何が違うか、っつーと前者はエラーに慣れてるんだよ(笑)。エラーを喰らった経験数が天文学的な数字なんで(笑)、エラーにビビらない。そしてエラーの原因を発見して対処するのが上手い、ってのが極論プログラミングに慣れてる、って事なわけ。
今回の破壊的変更の例にしても、「今回で完全に覚えた!」ってのが望ましいけど、そうそう上手く行くたぁ限らない。ウッカリ同じミスやっちまうのが人間なんだよな。
ただ、「あれ、これっていつか見たエラーだぞ?」ってのを覚えてるかどうか、って事だよね。いや、Scheme上で、って事に限らず、将来使う「全く違うプログラミング言語」でついついやっちゃう可能性はいつでもあるわけだ。その時、対処法を知ってるかどうか、もっと言っちゃうと「対処法を知る」為にはその前に「死ぬほどエラーを喰らった経験があるかどうか」ってのが重要になる、って事なのよ。
そしてプログラミングに於いてはプログラムを書いてる時間よりデバッグ時間の方が結果長ぇ、って事なんだよな(笑)。
なお、たまに教えて!gooなんかで「プログラミングするに必要な才能は?」とか言うクッソくだらない質問が投げられるんだけど、才能はともかく、意外と性癖がMの方が向いてるとは思う(笑)。「エラーで怒ってくれてありがとうございます、インタプリタ様!」みたいな(笑)?
ちなみに、僕はSなんで、そういう意味ではプログラミングに向いてません(笑)。エラー見かけるとパソコンを蹴倒したくなるタイプなんで(笑)。
![](https://blogimg.goo.ne.jp/user_image/02/d1/869657cd975cf72e89f9a3428d66e69e.png)
ちなみに、これ教科書では普通に演習としてノーヒントで書かされるんだけど・・浅井先生結構キツいなぁ・・(ま、そこは講義でフォローがあるのかな?)。
問題はやはりmatch-let(((p . v)(saitan_wo_bunriCR rest)))の部分かな・・。ここで再帰が入るってことはpとvに入るのは果たして?クイックソートの時にも途中で再帰が入ってきてこんがらがったなぁ・・要するに真に理解してないな。
ちょっと途中で変数の表示を入れて流れを追ってみる?と思ったけど・・意味ないか
こういう場合には、ANSI Common Lisp由来のtraceを用いて処理を追っていくのがセオリーなんだけど・・・・・・(※1)。
ただし、そっちが問題じゃなくって、レコード型にRacketで言う#:transparentがねぇのが問題なんだよな。
![](https://blogimg.goo.ne.jp/user_image/7c/49/261d0cb6ac24eb74ff2a09934e9eeef5.png)
これじゃ何してんだかサッパリ分からん(苦笑)。
Racketで見ると再帰の過程は次のようになっている。
![](https://blogimg.goo.ne.jp/user_image/49/fc/1cf62309c90088d52dd9d4553cafa45f.png)
あるいは、ANSI Common Lispだとこうだ。
![](https://blogimg.goo.ne.jp/user_image/04/b7/e59aa994179736b3044c31f3577218c1.png)
![](https://blogimg.goo.ne.jp/user_image/38/44/ce149cc37416a1cd465f9c31c6760755.png)
この辺で再帰の動きを追ってみて頂戴。
(多分手元でやるならRacketの(require racket/trace)のtraceが有効)
![](https://blogimg.goo.ne.jp/user_image/2c/f3/3752ae2b6394b422548bbf9f31a72627.png)
考えることしばし・・どうもソートしてるんじゃないな。先頭が最小だったら後の並びはどうでも良さそう。
その通り。
ある段階で先頭が最小だったとしたら、それと「新しく来た値」を比較し、小さい方を先頭にconsしてるだけ。
つまり、結果のリスト全体に対して作用させてるわけじゃない。
![](https://blogimg.goo.ne.jp/user_image/4d/69/5be3a8101890ca0fd87af6e09ab254ee.png)
続いてmatch-lambdaを。説明は意味不明だけど・・
ホンマ、RacketってScheme系の処理系ではWebページのデザイン自体はイカしてるんだけど、説明が全くない方が多いと言うサイテーなマニュアル/リファレンスなんだよな(苦笑)。
これ、ちなみに、両者ともマクロなんで、"Equivalent to ...." ってのはマクロ展開されてlambdaとmatchを使った式に展開されてます、っつってんだけど、ユーザーから言わせれば単に「実行例」が欲しいトコだよな(苦笑)。
だからこの辺でもGaucheのリファレンスの方がやっぱり読みやすいんだよなぁ。
![](https://blogimg.goo.ne.jp/user_image/73/8d/a0d054859588f68ce2f77ce9178da643.png)
要するに挙動が全然分からないのだった。昨日4時間、本日6時間くらい考えたけど無理だった・・。
これも、traceをかけてみればいいんだけど、生憎、Racketのtraceは組み込み関数のtraceは出来ない。
つまり問題は、中身が再帰である組み込み関数foldrのtraceが出来ないんだ。
そこでしょーがねぇんで、ここだけはfold-rightを自作してtraceをかけてみる。
![](https://blogimg.goo.ne.jp/user_image/00/34/f9b0ea1ff1579106e57d0f80b2d37d97.png)
![](https://blogimg.goo.ne.jp/user_image/59/62/04d4511036619241616eae87cd0fc090.png)
ANSI Common Lispでもreduceにtraceをかける事はエラーにはならないんだけど、残念ながらやっぱり組み込みの関数に関しては内情を追う事は出来ない。
そこで、やっぱりfold-rightを自作して、traceで追ってみた結果が以下のようになる。
![](https://blogimg.goo.ne.jp/user_image/47/b3/715a5808f659c4173f78b7bae1cd4db8.png)
![](https://blogimg.goo.ne.jp/user_image/09/98/5e99339aad57bd83ac6bf0139ba03631.png)
これで挙動が少しは分かる事と思う。
> 2022/10/07
バイトの待機時間で問題のfold-rightのところを見てます。再帰じゃないと思ったけど見直すと(rightなので?)ケツから最小値が先頭に浮き上がってきてる感じでやってる事は再帰版と同じでは?
そう、fold-rightも再帰プロセスを結果抽象化してるだけ、なんで、やってる事は再帰版と全く同じです。
※1: ちなみに、過去にもtraceに関しては書いてた筈なんだけど、存在を忘れてた、と言うのなら、それだけtraceを使わなくても再帰が書けるようになってる、と言う意味であり、否定的なニュアンスは実は全くない。