星田さんの記事に対するコメント。
> 2022/09/17
インクルード?
cond-expand?
この辺、やっと待望の機能がR7RSで(正確に言うとR6RS辺りから)追加されたのね。
実は、R5RS辺りまで、Schemeには「ライブラリ読み込み」関係の機能が全くなかったのよ(笑)。ファイルを全部読み込むloadくらいしか持ってなかった。
例えば、SRFI的なライブラリを読み込むとして、Racketだとrequireでしょ?ところがGuileだとuse-modules。Chicken Schemeだとimport。Gaucheだとuseだ。
各実装バラバラなんだけど、そもそも、「書類として仕様書を書くのは何故か」と言うのは、旧PLT Scheme上で書いたコードをGaucheでも「問題なく」動くようにしたいわけじゃない(笑)。でもこれじゃあポータビリティにはならんよな、って話で(笑)。実装依存で殆ど書かなきゃいけないんだったら、実用的な話だと「仕様書があったって」意味がねーだろ、って事になってたわけ。
んで、肥大化したR6RSだけど、この辺メスを入れたんだよな。これでこの辺の「ライブラリをコードへ導入する際にどうするか」って言う指針が出来て、それがR7RSにも入ってきたわけだな。
だから意外かもしんないけど、includeとかcond-expand(※1)等はSchemeでは結構新機能です。
そのままの形だとエラー・・
うん、分かった。凡ミスだ(笑)。
ええとね、そこのエラーってのは
「構造体(レコード型)ekimei_tは関数じゃないのに関数として適用されてます」
って事だ。
ウッカリしてた(笑)。
多分こう書き直せば素直に動くよ。
さぁ、間違い探しだ(笑)。どこが違うだろ?
そうね、終了条件のトコ
(ekimei0) -> 修正版: `(,ekimei0)
が違う。
前者だと「ekimei0は関数で実行されなければならない」。しかし、ekimei0は関数じゃないんで、「実行できへん」って言って怒られてるわけだ。
従って、原理的にはそこは、(list ekimei0)じゃなきゃダメなんだ。
ちとOCamlのリストの表記法に引っ張られたかな。
ゴメン。
> 2022/09/18
で、Foldを使ってLengthを作る。ほほう・・?仮引数がfirst rest_resultって事はfirst に lst、rest_resultに0って事?lstはただのカウンタになってるからコレで良いってことかな・・
ちなみに、僕ならこう書くかな。
ちょっとその例だと冗長だよね。
実際、OCamlでも似たようなカンジで書ける筈なんだが。
応用版でリスト内の文字を合体させるconcat。実は空の文字(列)を""って表現するってのが分からなくて時間を食ってしまったのでした。こっちが本来の使い方ですなぁ。
ちなみに、その関数がSRFI-13のstring-concatenateにあたる。
続いて素数を返す関数。funって?と思ったらどうやらLambdaらしい。え?これで素数の判定できるのか・・?これ書いてて改めて疑問に思ったので次回、同じことをSchemeでやってみるとして・・
このアルゴリズムは世界最古のアルゴリズム、とも呼ばれるエラトステネスの篩(Sieve of Eratosthenes)。関数名sieveってのはこれから来ていて、英語でsieveは篩(ふるい)の事。
答えを見ずに自分でやってみようと思って行き詰まったので、とりあえず検索してみる。なんでiに2ずつ増やしてループなんだ・・1じゃなくて・・というので詰まったのでまた次回考えることにする(^_^;)
実は素数は、2以外は全部奇数だ。
と言うのも、そもそも偶数の定義が「2で割り切れる数」な以上、素数の「1とその数でしか割り切れない数」と言う定義から考えると、2以外の偶数は全て素数としての定義を満たさない。
よって、別にループ自体は本質的には1づつ増やしても構わないんだけど「効率の問題」から言えば、2以外の偶数をチェックする必要がないわけ。
だから2づつ飛ばしてループするわけね。
最初自分でやってみるか?と思って素数判定述語を作ろうと思って「はっ!?」として立ち尽くしてしまった。条件分があってるかどうかは別にして、後半...(mod n (;nより小さな数)ってトコロ、filterとかmapとかで任意?の数nが選ばれたときに、リストの中のnより小さな要素ってのを自動的に設定するってどうすればいいのだろう?と。リスト内にある要素を比べるのであれば分かりそうな気がする(気がするだけ?)のでとりあえず置いといて、今回みたいに、ある範囲の数を自動的にチェックする場合ってどうすれば良いのか
この辺、なかなか奥深い話だ。
ある範囲の素数を調べるprime?を定義するには、prime?が全素数を知ってなきゃならない。果たしてそれを知る事が出来るのか?(※2)
SICPを参照してみよう。これがなかなか難しい話だが、Schemeにはprime?が全素数を「知ってるフリ」が出来る機能がある。そう、遅延評価だ。
もう一つ、SICPで紹介されているのが「確率的にその数が素数か否か」を判定するフェルマーテストと呼ばれるものだ。「確率的に」と言う事は、ハズレる場合もある、って事だが。
他にWikipediaではミラー=ラビン素数判定法、AKS素数判定法、等が紹介されているが前者はやっぱり確率的、後者は計算時間に欠点がある。興味があれば実装してみても良いでしょう。
Wikipediaには他にも素数判定法が色々と紹介されています。
このタイミング、そして例としてゲームブックを出されてるところからして何かあるのかも?とか。いや、あれですかね、夏休みの工作。まあ衣替えの時期までにはテストデータとエンジン部分を作る気満々です!
そう、星田さんがADV作る、っつってたのもあるし、僕も今ちょこちょこコード書いてて、それに利用出来るかも、ってのがあって、タイミング的には丁度いいかもな、と言う話です。
> 2022/09/21
基本的な書き方がわかったのでOcamlの直訳版を書いてみる。<>はnotだと思ったんだけど・・しっかりと6とか9とか入ってるし・・うーん・・
いや、合ってる。
間違ってるのは入力の方だ。
OCamlのコードの方のデザインレシピでの記述を良く読もう。
(* 2 から n までの自然数を受取り、2 から n までの素数を返す。 *)
結果、5からのリストを与えてるから計算結果が違うわけ。
※1: 元々はSRFI-0の提案。そもそもSRFI自体が「各実装にこれらの機能があればいいのに(ついでに仕様に含まれて欲しい)」要望集なんで、映えある「一番最初の」SRFI-0の提案は、実装毎にコードを変えなアカン際に、それらのコードが各実装で問題なく実行されるような「指示機能」の提案だった。
※2: 素数の「出現」に規則性があれば、そのルールを適用して「ある素数の次の素数が何か」簡単に予言出来る。
しかし、現代でもそのルールはいまだ見つかっていない。ハッキリ言えば、数学者が現時点でも血眼になってそのルールを探している最中だ。
懸賞金付きの数学の未解決の難問の一つにリーマン予想と言うものがあり、これが解ければ素数の謎も解けるのでは?と言われている。
なお、コンピュータにとっての素数はコンピュータにとっての円周率と似たようなモノで、現在でも「最大の素数の値」は順次更新されてて、現在(2022年時点)で知られてる「最大の素数の値」は 「2の82589933乗 引く 1」だ。
Wikipediaでは大きさで上位20個の素数が紹介されている。