概要
継続の使える schemeを作ってみたくなった。
(Common Lispのサブセット(関数100〜200程度)は今まで5回ほど、作った事があるが、schemeを作るのは、はじめてである)
そこそこ、うごくようになった。
R7RSのpico仕様というのがあり、それが動くか動かないか程度の出来栄え。
実装言語はJavaで作っている。
ふいに、Graalで動かしてみたくなった
普段はOpenJDKなのだが、Graalでがんばれば、Nativeコンパイルできるのだろうか?
自宅のMacにGraal入れてみたよ。
SDKMANを入れていなかったので、入れてから、
sdk install java 21.0.4-graal
ORACLEのGraal Ver21を入れてみたよ。
うーん、antでコンパイル出来なくなった
デバッグ用のログを吐くのに、slf4jを使っているのだが、そこでコンパイルが通らない。
もう1つはSWINGのGUIで、コンパイルエラー。
色々調べたら、Graalでコンパイルする時は、ソースが必要みたいだ。
とり急ぎ動かしてみたかったので、slf4j-apiのソースだけ落としてくる & SWING-GUIのソースは削除してみた。
antでコンパイルできた。
ワーニングがいっぱい出たけどね。
証拠画面キャプチャー
Graalですが、nativeコンパイルは、まだ行っていません。
java -jar lisp-0.1.jar
で、起動すると、slf4jの実装がないよと、メッセージが3行出ている。
(当然ですが このjavaはGraal Ver21です)
メッセージが3行出るのは、まぁ仕方ないな。
ちなみに、メモリはどれくらい食っているのか気になって、Macで調べてみたよ。
33.5MB か。思ったより随分と少ない。
いい感じである。
ちなみに、このLispインタープリタは、JavaのリフレクションAPIを使って、Javaで実装された足し算とかを呼び出している。
特にソース修正なしで、GraalVM(インタープリター)で動きました。
紫藤さんのScheme入門 16.継続はオススメです
このページ本当に、わかりやすい。神。
継続(call/cc)を一度も使った事ない、私でも、なんとか理解できた。(少しだけ)
ここに載っているサンプルを、入力してみる。
紫藤さんの記事に書かれている答えと一致しました。
やったね。
(継続は難しいです。この答えはいくら?と聞かれて自分で考えたら、たぶん50%以上の確率で、間違える自信あり!)
R7RS pico
schemeのpico仕様というのがあって、以下にrustで書かれたサンプル実装がありました。
私が作っているJavaインタープリタは、まだこのpico仕様と、完全に同じ結果にはなっていません。
ちなみに Gauche(ゴーシュ)でも、やってみたんだけど、完全に同じ結果にはなりませんでした。
Print処理で、巡回リストの印刷にはじめて対応出来た。
今まで、何回かLispの実装はしているのですが、巡回リストの印刷にはじめて対応できました。
ちょっと、嬉しい。
R7RSの文字の仕様と、つちよし問題
R7RS-smallの日本語訳を読んでいた。
6.6章 文字に、以下のような事が書いてあった。
(char->integer char) 手続き
(integer->char n) 手続き
Unicode 文字が与えられたとき,char->integer は
その文字の Unicode スカラ値に等しい 0 から #xD7FF の間,
または#xE000 から #x10FFFF の間の正確整数を返す。
非 Unicode文字が与えられたときには,#x10FFFF より
大きい正確整数を返す。
これは,実装が内部的に Unicode 表現を使用する
かどうかとは真に独立している。
char->integer が適用されたときにその文字が返す値の正確
整数が与えられたとき,integer->char はその文字を返す。
これって凄くないですか?
私、会社では、JavaでWebシステムの開発をしています。
1年ぐらい前だったか、社内用のシステムで、文章入力欄に
「𠮷田さん」と書いたらエラーになるという報告を受けました。
吉の上の部分が、土になっているのを、「つちよし」というらしいのですが、
この文字は、Javaではサロゲート・ペア文字となってしまいます。
サロゲート・ペアでバグってしまいました。
でも上のR7RS-smallの文字仕様を見て、素直に実装すると、サロゲートペア文字を根絶できそうな気がします。
自作のpico schemeでも、「𠮷」が、「1文字として扱える」ようにすべく絶賛バグ出し中です。
StringBuilder に appendCodePointというメソッドがあるんですね。
appendCodePoint(int codePoint)
codePoint引数の文字列表現をこのシーケンスに追加します。
1文字をcharではなく、intに入れてから、処理をしています。
こんなメソッドがあるとは知らなかった。
大変勉強になりました。
まとめ
個人的な見解ですが、自分がlispインタープリタを作るのだったら、一番慣れているJavaか、今勢いのあるrustのどちらかと思っています。
昔だったら、JavaVMの上で動く、SchemeのVMという事で、動作が遅くなりそうでした。
しかし近い将来に、GraalVMのNativeコンパイラによって、スピードも改善されるでしょう。GraalVMに大変期待しています。
それから、 R7RS picoの ソースを使って、rustの学習中です。
(60歳過ぎると、もの覚えが悪くて困りますが)
そのうち Graal の nativeコンパイルも、やってみたいです。