Lisp Scheme Part41
>>546
ここでアイスランド語が言及されるとは驚きました、アイスランド語は実に濃ゆい言語ですね
教科書(Johns Hopkins) を買ったけれども、当然 1 ワードも読めませんでした schemeはじめましたなんだけど
[lisp1.0+]label, [cl]labels = letrec + let name
[cl]flet ((f (args) fletbody)) body = let ((f (lambda (args) body)) letbody)
って理解でいいの? おおよそ似た雰囲気では書けたりするのかもしれないけど
単純に対応してるわけじゃなかったりもするからいいかどうかは状況によるんじゃないの。 まんまじゃね?
とりあえず(macroexpand 'sb-int:named-let)はそのまんまlabelsに展開されたのでお試しあれ
どの処理系でも似たような定義が大体あるはず
1958年のオリジナルlispのlabelは、scheme界隈ではlet1という名前で見掛ける
当然だけど、ローカル定義が一つなので(自明には)相互再帰はできない
触って気付いたけど
(flet ((cons (a d) (list :cons a d))) (cons :a :d))
; (:CONS :A :D) clisp, sbcl
; (:A . :D) ecl
eclのこれバグ? 触ったことないのでeclがどの程度cltl/ANSI/clhs等の標準をリスペクトしてるのかも分からないのだが
とりあえずgoogle play storeからeclのandroidポートらしいeql5 replを入れてみた
(list ;; attempt to shadow cl:cons
(flet ((cons (x y) (cons y x)))
(cons 'co '?ns))
(let ((cons (lambda (x y) (cons y x))))
(funcall cons 'co 'ns)))
((CO . NS) (NS . CO))
fletは謎挙動だね…
* shadowしない名前(xcons)ならok
* (flet ((cons (x) (1+ x))) (cons 42))がアリティ不一致で怒られる
から推測するに、普通cl packageの関数なんて弄られないだろうと踏んで、関数の名前解決を手抜きして最適化してるんだろう
値の名前解決は特に弄る意義もないので、scheme風にlambdaをletで値として束縛して呼べば問題ない
clを名乗る以上はオプションで切れるくらいの配慮はあるだろうから、eclにこだわるならマニュアル読んでみては
少なくともclhsはリスペクトしてないね
...flet can locally shadow a global function name, ...
http://www.lispworks.com/documentation/HyperSpec/Body/s_flet_.htm | 彡⌒ミ
\ (´・ω・`)名前のシャドウ化辺りって自分で処理系実装した子はわかると思うけどハゲる要因だから絶対関わらない方がいいと思う
(| |)::::
(γ /:::::::
し \::: eclは有名だけど、embeddableの名前通りの用途で1MBちょいな処理系だから、そういうものと割り切って使うべき
funcallが冗長ならletのbodyにfuncallをconsするだけのmy-fletを作ればいいじゃない
(さらなる災禍を招きそう) eclのlocked packageなる概念やcompile-timeの意味論に関連しそうなissue
2 yeas agoだけど
https://gitlab.com/embeddable-common-lisp/ecl/-/issues/574 >>553
特定の名前の解決を決め打つ言語は多いし、そういうポリシーもありだと思う
普通でないのはcondition(warning)を挙げないところ
決め打つ名前(locked package?)が分かってる限りは、flet/labelsのレキシカル束縛リストから拾った名前がbody内の呼び出しformのcarに存在するか、ランタイムコストの無い自明な静的解析でconditionを挙げられるはず >>550
等価と思って良いよ
伝統的なlisp(とcl)のように(let ((x '())) ...)を(let (x) ...)と略記できない、だとか細かい差異はあるけど
百聞は一見にしかずなので、構文の対応を見るのが手っ取り早い
あとeclのname collisionの件、consの例(>>553)はさすがにcontrived-exampleだと思うので、ついでにeclで破綻するように
letrec/nlet/labels で定義するラベルとして、所謂accumulatorイディオムにloop(他にはlp, iterとか)を使うのが慣例だけど、eclではcl:loopと読まれるのでは?と予想
;;; cl -- ok: cmucl, sbcl, clisp, gcl err:ecl (的中)
(defun fact (n)
(labels ((loop (k acc)
(if (= k 0)
acc
(loop (1- k) (* k acc)))))
(loop n 1)))
;;; scheme -- ok: guile
(define (fact n)
(letrec ((loop (lambda (k acc)
(if (= k 0)
acc
(loop (1- k) (* k acc))))))
(loop n 1)))
pcでテストはしたけど、スマホから手打ちなので変だったらごめん >>557
スクリプト言語 (処理系) 的な想定だと実行開始時にテキストの解釈から毎回やるので
静的解析もランタイムの一部みたいな感じになる。
この場合に限って言えばどちらにせよ名前のルックアップはやるのだからそのときにわかるだろうとは思うけど
静的解析を頑張らないという方針はあり得るんじゃないの。 Gauche で検出されないエラーで (let ((0 1)) 0) みたいなのがあって、
実際にはオプティマイザが消去してしまうんだそうな。
文法の解析で通したものをオプティマイザがエラーとして弾くのも変な話だし、
オプティマイザが走査することがわかっているものを前段階でもチェックするのは二度手間だし、
オプティマイザを密結合してしまうのも保守しづらいし……
という葛藤があるのはわかる。
まあそれぞれに事情があるので原理的に可能だからといってそうすべきだとも言えない気がする。 0はシンボルじゃないから、文法解析を通しちゃ駄目だろw そういう手では絶対書かないだろう変なコードも、マクロ書いてるとまれによく発生するから困る カウンタ変数を捕捉更新しようとして、うっかり評価してしまったケースとか 多分(let ((i (+ i 1))) i)が化けたのかな letの時点でオプティマイザに通してんのかな
let系はlambdaまで落として((lambda(i) i) (+ i 1))とすれば間違えようがないと思うのだが エスパー大会か?
(let ((i (+ i 1)))
(another-macro i))
another-macroは副作用目的で自明にiに展開したか、乗法的な関数を呼んだ(iの初期値0*n=0) >>565
gancheは知らんけど、さすがにletはプリミティブな事が多いかと
むしろ最適化で読み飛ばすならlambdaまで還元してしまってはダメで、LETをヒューリスティックに認識する必要がある
仮に評価順を示す為にバッククォートでわざとらしく書くと
`(let ((,index ,(1+ stride))) ,(* index stride))
; (LET ((0 1)) 0)
(に等価な)展開とかがありがちかな
特に例に意味は無かったってオチだったりして defmacro/macroexpand方式だと特にだけど、(let ((0 1)) 0)みたいな残骸から推論する技能はとても大事に思う
書く時もそうだけど、人が書いたモノの後始末なら前提知識が無いのでなおさら
これだけ想像を膨らませてくれる貴重な(let ((0 1)) 0)すら消し飛ばされるならもうお手上げ
なんて文句を言いつつ、schemeでもついslibのdefmacroに手が伸びてしまうのだが >>565
論理的にどんなletが束縛リスト(とおそらくbodyも)を読み飛ばせるかについて補足
letフォームの評価値は最後のフォームの評価値(car (last 'let-form))のみで決まるけど、それが再束縛のできない自己評価オブジェクト(0, T/#t, :kw-symb etc)ならば、単にそれを返すだけで他を一切見る必要すら必要がない
(let dont-care/maybe-invalid self-evaluating)
→self-evaluating
もしそれ以上簡約してしまうと、(eq 'let (car 'let-form))と(car (last 'let-form))だけを見て決められない 一応値については正しいというだけで、もしbodyに(exit)や大域脱出が入ってても無視するのか?という問題はある
ill-formedな>>560すら無視するのだから、当然well-formedな(exit)も無視するのが自然だけど、実際のところはgaucheに訊いてください >>570
念のために補足しておくけど >>560 のケースは捕捉されないエラー
(現時点では捕捉することを意図的に諦めているエラー) であって
Gauche の仕様として正しいというわけではないよ。 結果は未定義。
直接的に書いてしまった場合にしてもマクロ展開結果でこうなるにしても
あくまでも誤っているプログラムだからね。
言いたかったのは >>557 に対してで、原理的に出来てもやらない事情の例として
(私は ECL のことは全然知らないので) Gauche での例を出したってだけ。 >>571
どうも、俺のも原理的には…という同じ意図の話だよ
eclやgaucheが有名実装では最もアグレッシブな感じなのかな?
(declaim (optimize (speed 0) debug safety)
が外せない俺には怖くて触れないよ なおeclのlocked package?の件、標準の宣言を全て付けても有効な模様… >>572
> 有名実装では最もアグレッシブ
そんなことはないんじゃないかな。。
実行前の処理に時間をかけない (かけても総合的な性能向上にならない) という
判断でエラーチェックに消極的だけど最適化にも消極的だから。 UCB Scheme
https://people.eecs.berkeley.edu/~bh/61a-pages/Scheme/
UCB Scheme is a modified version of STk 4.0.1 by Erick Gallesio. USB Schemeじゃないのか
どっちかって言えばUSB Schemeが欲しいのだが そのリンクがどうしたっていうんだ?
何か思うところがあるなら話題に挙げるのはかまわんが
ただリンクを置いて去るのはやめて欲しいな。
ニュース系のネタならお知らせの意味で貼ったのかなと思うところだが、
そういう感じでもないみたいだしな。 そもそもダイナミックスコープの何がだめですか
Emacs lispはダイナミックスコープですが、
あちこちから呼ばれてる関数を、空関数で上書きして殺すとかできて便利です
Emacs lispの感覚でGIMPのスクリプト(scheme)を書こうとすると
なにか何でもかんでもラッパー渡し(いちいちcarをひとつ辿る)って感じです
ちなみにLispは普通の手続き型言語としてしか使ったことないです
そんな奴への説教とかあったら聞きたいです
マクロとか、「確かにif文を関数として実装するのは無理かもしれないし、
そういう時に使うのかな」くらいにしか解ってないです >>581
全然ダメじゃないよ。でも誰か(昨日のオレ)が余計なことをやって不審な挙動をしてるけど原因がさっぱり分からないというのは起こりやすいかもしれない。 Lispではたまたまうまく動いてるように見えるけど変数宣言の無い言語でダイナミックスコープやると死ぬ >>581
元のプログラムを書き換えずに影響を差し込むことが出来るってのはアプリケーション拡張用として便利だけれど
元のプログラムが想定してない滅茶苦茶なことも出来ちゃうということと最適化が困難になるのが深刻な問題だと思う。
ユーザーが変な使い方をして変なことを起こす分には自業自得といえるにしても
今ではパッケージをネット上からダウンロードしてインストールまで自動だから
悪意あるコードが他のパッケージを好きなように変更できるようだと影響範囲が大きい。
たとえばウェブブラウザのアドオンなんかだど各アドオンは通信によって協調は出来るが
環境は共有しないようにすることで影響力を制限している。
参照しているものがことごとくいつでも変更される可能性があると
インライン化や畳み込みといったごく基本的な (しかし効果が高い) 最適化すらできない。
現代的な言語処理系に対して数十倍単位で遅いのはさすがに困る。
ものごとの良し悪しにはトレードオフがある。
どちらの問題もコードが小規模ならどうということはないので利点のほうが上回っていたのかもしれないが、
時代を経て巨大になりすぎた。 疎結合を意識した構成にしないと手に負えない。 グローバル&ダイナミックは罠になり得るけど、対話的に使うコマンド言語(シェル)は大体そうだし利便性の問題、新しいpwshでももそう
定義をテキストとして全てダンプして、読み戻せる利点がある
cl/scheme(fluid-letとかそんな名前の拡張)のように基本レキシカルで、ローカル&ダイナミックは宣言が必要なら意図せず使う事は稀なはず
(form-in-scope? (declare (special x)) form-in-scope)
(locally (declare (special x)) (form-in-scope))
面倒だけど(declare…)が外、つまり同じレベルのフォームに影響する場合があるのが気持ち悪いから、明示的な後者を好む レキシカルな情報を取り込んでしまう(暗黙にクロージャを作る)クロージャにはテキスト表現が無いから、ダンプが出来ないのは致命的な欠点
よってダイナミックスコープ一択になる
pwshだと gci function:
bashだとdeclare -f (多分、よく知らん)
でダンプ、出力されるテキストを読み直せば(大体)環境が復元できる
pwsh方式だと{code}.GetNewClosure()でクロージャは明示的に得る >>581
guileだっけ?
あれ変な拡張山盛りだから出来るんじゃない?fluid-letみたいな名前がないかaproposしてみたら >>587
GIMP の Scheme (Script-fu) は TinyScheme が使われている。 (昔は SIOD だった。)
まあ fluid-let くらいなら自分で書いてもたいした手間じゃないけどね。 #<closure ...>が嫌ならいにしえのfunargを使えばok
別にレキシカル環境をリストで持ったって構わないわけで、印字表現が不透明なlispはインクリメンタルコンパイルやリストより効率の良いデータ構造を選んだ結果
厳密にはダイナミックスコープでないけれど、コード注入なら'ラムダ式を渡して廻っても同等の自由が得られる(call by name)
既存のコードの方でも準備が必要だけど >>588
ええ…gnu公式の拡張言語とは一体なんだったのか >>590
アプリケーションに特有の機能はアプリケーション側で用意されたものを呼出して使うわけだし
言語側のライブラリはほどほどで足りるんで小さい処理系のほうが面倒がないというのはあるかも。
Guile はビルドするだけで面倒くさいが TinyScheme はファイル数個の簡単構成だし。 ローカルにダイナミックな束縛をやるなら、それ専用のprogvフォーム(clにある)はどう思われてるんだろ?
(progv 変数リスト
値リスト
body)
let系列の (変数 値)リスト慣習を転置(zip)した記法だけど、束縛が多くても縦にスペースを取らない
let慣習では変数 値はsetq/set!だけど、progvの変数リストは評価されるから、リード時にバッククオートでシンボルを埋め込むようなハックが不要
動的束縛を活用するようなメタな場面では特にだけど、埋め込む為だけにわざわざリーダを何度も通すのが歯痒い
多分に個人的な好みだと思うけど >>592
転置されてるのと束縛リストの実行時評価は、おそらくlet風のマクロを書く時に便利だからかな
mapcar #'list let-like-binding-list
がprogvに渡せて、あと欠損値も勝手にnilで埋まる
あと機械的に名前を処理するならgensymもお忘れなく 例が悪かった
単にlistをmapcarするだけでは、let形式のリストをそのまま渡した方が早い
不定数の引数を取ってリストを返す関数で、自明なlist以外をmapcarするならかなり楽が出来るはず
しかし何に便利か今すぐ具体的な例は思い付かない() >>591
俺環ではインストール(展開後)で50MBのディスク容量占めてるな
実験的なelisp対応(編集機能無しで一体何の意味が?)とか
興味深いけど謎な方向に突き進んでるね GNUは昔から他人の成果物の丸パクリしか脳が無い団体だよ emacsの膨大なテキスト処理関数群に依存していない純ロジックのみのelispコードなら資産になる
そんなの指折り数える量だろう ライセンス問題でどうしてもコードを触りたくないなら別だけど
何らかのlisp書きであれば、コピペしてその方言に適合するよう手直しする程度は自明な作業でしょう >>598
ダイナミックスコープとレキシカルスコープでは埋めがたい差があるし、モジュールやフェイズの方針なども大きな差だ。
伝統的に方言と称してはいるが個々に定義された別の言語なのでそんなに簡単に修正は出来ないよ。
私自身はそこそこ Scheme には習熟している自信があるが Common Lisp も Clojure も全然わからん。
C と JavaScript の外観はなんとなく似せてあるが静的型と動的型の違いという根本的な部分で違うからそう簡単に移植はできないのと同じような感じ。 いっそ Emacs そのまま組み込んじゃうとかそんな方向に進まないかな…
近頃の環境ならそんなに重くないはずだし。 >>600
やってできなくはないのかもしれないよ
昔、zlibがまだなかった時代にDOSでzオプションの利くtarを使いたくて、
仕方なくtarとgzipをまとめて一つのバイナリにリンクしてしまって、
スタートアップでヒープを半分に割って、スタックをそれぞれに割り振って、
あとはバッファが一杯になるたびにtar側とgzip側をsetjmpとlongjmpで行ったり来たり、
解凍は問題ないんだけど圧縮がどうしても同じ結果にならなくて、発表せず一人で使ってた オレオレSchemeでMineSweeper
ソースがSchemeで書かれている
ttp://ujip.ninja-web.net/schemeonjs/minesweeper.html だからなんやねん
つか何年前から来たの?ってレベルの話だろ オンラインでuLisp動かしてみようかとTinkerCADのArduonoUnoにソースコード流し込んでみたけどさすがに5000行は許してもらえないみたいだな。 最適化されたCLは最適化されていないCよりは速い
昔Common LispでCより速いHTTPパーサを書いたとか言ってたのを見かけた
コードを見るとnodejsのCで書かれたHTTPパーサをパクったみたいな感じなのに
比較対象はなぜかどっかの個人がCで書いたHTTPパーサだった
その個人が晒してたソースのMakefileはデフォルトでは最適化なし
なぜ比較する前にCの方を最適化することを思いつかなかったのだろうか
というかなんでnodjsの方と比較しなかったんだ?
誰か理由わかります? scheme処理系作ったりSICPで悟り開いたりしたけど今の使い方は実質電卓
スペース区切りの値そのまま貼り付けられて便利なんよなー John Cowan 氏が R7RS-large の議長の座を降りることを表明した模様。
これからの体制については現時点は決まっていない。 実質機能しない規格なんて不要
主要処理系の実態調査して
ANSI Common Schemeを策定すべき 実用的で無い言語にANSI規格とか要らないだろ
それより、Type Script 普通に良い言語だぞ、
あれ実質的に型付きのlispだわ 「Type Scriptはlisp」発言頂きましたー >>615
設計者の「そうしたかった」という発言が拡大解釈されたもので、
インタビューをちゃんと読むと「そうできなかった」ということも言ってる。 How to Design Programs, Second Edition
https://htdp.org/2023-8-14/Book/index.html
新版出てた Chez Scheme の 9.6.2 が五日前にリリースされていた。 Gauche 0.9.13 のリリース候補が出た。
問題ありそうな部分や要望があるなら今のうちに出しとくといいよ。
https://sourceforge.net/p/gauche/mailman/message/41039777/ Gauche1.0.0 !! 早く来てくれーーー!!! Gaucheの目的が何なのか知らんけど
それが達成されるまで1.0にならんのだろうな Gauche のバージョンナンバーの予定はここにかいてある。
http://practical-scheme.net/gauche/devinfo-j.html
具体的な基準ではないので(ユーザーの意見を聞きつつ)開発者が納得する完成度になればメジャーバージョンもあがるってことだろ。 「Gauche 1.0」って文字列の違和感がすごい 要望ね。schemeは処理系としては構造が簡単だから適当に作ってもそこそこ良い具合に出来上がるだろうが、
問題はその後で、処理系の方向性を決める必要がある。処理系作るってことは目標が既に設定されている場合もあるが、
他人に使って欲しいのであるなら例えばpythonライブラリ流用できるとか.NETでGUIアプリ簡単に作れますとかwebだとか生成AIで何かいけるとかそんなのだね
俺がGaucheの名前を知りながら長年ほぼ触ったことないのはその辺りが原因だよ Gauche の目標設定はトップに書かれている。
http://practical-scheme.net/gauche/index-j.html
要するにスクリプト言語として常識的に必用とされる機能を盛り込んで日常業務に使える Scheme 処理系を目指すってことだ。
英語の「日常会話程度」が専門的な会話より難易度が高いなどといわれることもあるように「普通に使える」ってのは何か特徴的な売り文句があるより大変だったりもする。
Gauche は作者自身が業務で使ってるわけだから特化するより万能寄りのデザインなんだろう。
個人的には日本語テキストを不自由なく扱えるのがありがたいね。開発が始まったきっかけも stk で日本語を扱えなかったかららしいし、そこらへんは力が入ってると思う。 schemeを好きで使ってるやつって俺含めて既に自分の処理系は持ってると思うのだが、
自分の欲しい機能を満たせばそれ以上求めないし、その成果を踏み台に次のステップへ階段を上がるだろう
階段を上った末、他人に使わせる場面に出くわす事は良くある事で、その時それはschemeではなくなってた方が良いかもしれない
新人「えーなにこの括弧だらけ…今のトレンド?か、かっこいいですねワラワラワラ(辞めよ…)」
業務で使ったら他人を辞めさせる能力については万能になれるか 次のリリースはついに1.0だと>Gauche
お祝いしなきゃ expecting ってのがどのくらいの確信なのか感覚的にわからないのだけど
一応の既定路線くらいには考えていいんかな? しらんがな
どうせ本人もここ見てるだろうが質問あるなら直接本人に聞けよ
答え難いだろうが Chez Scheme 10.0.0 リリースきた
https://github.com/cisco/ChezScheme/releases/tag/v10.0.0
サポートするアーキテクチャが増えたってのと、
そこにポータブルな仮想マシンも追加されたというのが
かなり大きい変更点らしい。 GuileとGaucheって、VMインタープリタ、Cプログラムとの連携・拡張、オブジェクト指向あり、もともとR5RS。
フリーソフトウエアやライセンスという点以外は、言語・実装の方向性としては似ているように思いました。
Gaucheが、BSDライセンス版Guileのような感じがしたのですが、みなさんどう思いますか? ガイル?
>>634
まじか?>>1のスレにAAあるから見てこいよ Sagittarius 0.9.11 も来たよ〜〜〜。
https://bitbucket.org/ktakashi/sagittarius-scheme/wiki/Release%20Note%200.9.11
Sagittarius は暗号通信系に強いね。
作者はオランダの銀行システムに関与する技術者だそうなのでその経験が活かされてるんだろう。 【検証】40時間Lispを勉強したら信者になれる?【Lisp1】
https://youtu.be/V2GM9lR-Di0
Lispの勉強をしたら『葬送のフリーレン』と同じカタルシスが待っていた。【Lisp2】
https://youtu.be/JvsSt_ksKiw 神の言語からschemeを経て生まれたjavascriptは人間にとってはちょうどいいバランスだったわけだな それの前にポールグレアムいじり回が3回あって
それで「Lispがそんなにすごいなら」ってことで40時間勉強したというわけだねw ポールグレって本職の人じゃなかったんだな
すごい熱量な感じなのに MIT卒でLispで儲けたあと、ベンチャーキャピタルになった元本職かな エッセイストだと思うけどマとしては通販サイトとか作ってたんだっけ
ただ小さな関数やマクロutilが集まったonlisp.lispは準標準関数的な感じで愛用してます そもそもハッカーであるかにガンガンプロダクト作る的な意味での本職マか否かは関係ないと思うのです
cl&schemeの根幹や文書化のみならずC, Java, Fortran委員まで勤めた皆のSteele先生だって何作ったか寡聞にして知らんくらいだし
最近ではC,AWK,Goのバイブル+作法本で鳴らしたKernighan御大も隠居してエッセイストやってる
言語本+エッセイで良い書き物できるのがハッカーの十分条件だと思うね、pgrahamも余裕で該当