2 ポイント 投稿者 GN⁺ 2024-05-27 | 1件のコメント | WhatsAppで共有
  • Hurlは一般的な分岐や反復の代わりに、例外処理だけで制御フローを構成する実験的プログラミング言語
  • Nicole Tietz-SokolskayaとRecurse Centerの友人たちとの会話から始まり、サイトでは使い方のドキュメント、サンプル、デバッグ案内、Q&Aを提供している
  • 紹介ページの推薦文は「monstrosity is beautiful」「Certified unhinged™」のように、意図的に冗談めいた雰囲気を前面に出している
  • Hurlとサイトのソースコードは公開されているが、メールでパッチを送るにはパッチの権利譲渡が必要
  • ライセンスはAGPL-3.0、GAL-1.0、商用ライセンスのいずれかを選ぶ方式で提供される

例外処理だけを残した言語実験

  • Hurlはひとつの目的のために作られた: 例外処理ベースの制御フローだけで構成された言語が可能かを探ること
  • アイデアはNicole Tietz-SokolskayaとRecurse Centerの友人たちとの会話から生まれたもので、友人たちの身元は「品位のため」に公開していない
  • サイトではHurlの使い方ドキュメントとサンプル、デバッグ案内、Q&Aを提供している

冗談のように見えるが実際に公開されたプロジェクト

  • 紹介ページにはHurlの性格を示す推薦文が掲載されている
    • “This monstrosity is beautiful, and I must never touch it”
    • “Certified unhinged™!”
    • “is "🤮" an available quote?”
  • 追加の推薦文を載せたい場合はNicoleにメールを送る必要があり、引用掲載への明示的な同意が必要

ソースコードとライセンス条件

  • Hurl言語とこのサイトのソースコードは Hurl's repo で公開されている
  • バグや誤りを見つけた場合はメールでパッチを送れるが、パッチに関するすべての権利を譲渡しなければならない
    • 再ライセンスと商用ライセンスの可能性を維持するための条件
  • プロジェクトは次の3つのライセンスのいずれかで利用できる
    • AGPL-3.0

      • GAL-1.0: Gay Agenda License
      • 商用ライセンス
      • ライセンス検討の過程では joke licensesunfortunate licenses も考慮されたが、最終的に上記3つのライセンスが採用された

1件のコメント

 
GN⁺ 2024-05-27
Hacker Newsのコメント
  • プログラミング言語を設計するなら、include/import では 名前空間 を強制し、可能ならトップレベルの副作用も防ぐべきだと思う
    let foo = include "lib/foo.hurl" のように受け取り、foo.init() を呼ぶ形にすれば推論がはるかにしやすい
    逆に include "lib/foo.hurl" // side effects の後に baz(buz) が出てくると、関数や変数が標準ライブラリ由来なのか、どこかで include されたものなのか分かりにくい

    • 明示的な名前束縛がない場合は、import 文と名前空間を一致させるよう強制したほうがよい
      import "foo/bar" なら foo.* または bar.* を使えるべきで、bazz.* が出てきてはいけない。Go をまさに思い出す
    • 異論があるわけではないが、仕事で使っている IntelliJ はどの参照がどこから import されたのかを明確に示し、ショートカットで移動もできる
      VSCode もプラグインと LSP で似たことはできるが、かなり見劣りする。コードナビゲーションが遅すぎて VSCode では仕事にならない
      こうした提案は、その手のツールがないときにだけ有用なのだろうか。少なくともプロの環境では、そうしたツールなしでやっていくのは不可能に思える
    • こうすれば foo.init()引数 を渡せるし、素の import ではそれができない
    • 制御フローが例外中心の言語なら、もう「推論しやすい」という船は出てしまっている気がする
      だからといってこのプロジェクトに価値がないという意味ではなく、むしろアート作品だと思う
    • 100% 同意する
      Ruby を fork して require がシンボルテーブルを上書きしないようにしたことがあるが、Ruby のエコシステムは 共有されたグローバル可変状態 に依存しすぎているように思えて、結局 Ruby 自体への興味を失った
  • 例外は呼び出し元と呼び出される側の 契約 を把握しにくくし、コードの結合度も高めるので、昔から好きではない
    Go や Rust のように戻り値で処理する方式のほうを好む。ざっと眺めた限り、この言語にその問題を解決する要素があるのかはよく分からない
    IDE が関数の未捕捉例外をすべて動的に把握し、例外が投げられうる場所へジャンプできるなら、このモデルも悪くないかもしれない。ただ、結合度をどう扱うのかは分からないし、制御フローグラフは極端に不安定になりそうだ

    • Java では IntelliJ がまさにそれをやってくれる。例外を投げる関数があり、プロジェクト内のどこかの呼び出し元で捕捉されていないと問題として表示され、実装や呼び出し箇所にも簡単に移動できる
      ただし Java では、RuntimeException を継承していない限り、関数が投げうる例外は関数シグネチャの一部になる。そういう場合、シグネチャに追加せずに例外を投げるとコンパイルできない
      Java のこの条件は、IDE が未捕捉例外を報告するのをずっと容易にしているが、ランタイム例外でないなら静的解析で解ける問題でもある
      一方で、標準化された Ok/Err ラップ値を返す方式は、ツール支援と開発者の利便性の両方の面でより単純に見える
    • 例外を投げることと、例外を変数として返すことの間には、文字通り何の違いもない
      違いは、例外伝播方式ではコンパイラがやってくれる ボイラープレート を自分で手書きしなければならない点だけだ
      2024年にまともに動く頭を持った人が、なぜそんなことを手でやりたがるのか、まったく理解できない
    • Go がエラー文脈をあまりにも自然に飲み込んでしまわなければ、もっと好きになれたかもしれない
      使っていた間は、デバッガなしで 根本原因 を見つけるのがずっと苦痛だった
  • toss の例は「関数の外へ複数の値を渡すのに主に使い、必須ではないがかわいい」とされているが、役に立たないどころか 再開可能なジェネレータ を実装している
    もちろん、即座に再開する以外のことをさせようとすると、かなり面白くなりそうだ。コードベース全体を toss の内側と外側のスタックで構成すればいいだけだ

    • まったく同じではない。再開可能なジェネレータは、プログラムの後のどの時点からでも再開できるが、ここでは return がハンドラ側に レキシカルスコープ されていなければならない
      たとえば Python ではどこからでも next() を呼べる
      これは副チャネルでコールバックを渡すのに近い。toss がそのコールバックを呼び、return は文字通りそこから返るだけだ
    • 読んだ後の第一印象もまさにそれだった
      他の言語なら本当に有用な機能なのに、ここでは捨ててもよいかわいい機能のように扱っているのが、ちょっとしたジョークなのかと思った
    • スタックベースの イベント伝播 に近い
    • C# の yield のようなもの?
    • 最初の感想も同じだった。ジェネレータのある小さくて素敵な言語というのは悪くない
  • Hurl は Smalltalk や Common Lisp 風の 条件システム にかなり近く見える
    スタックの巻き戻しと再開は、可能なリスタートのうちの 2 つにすぎない: https://gigamonkeys.com/book/beyond-exception-handling-condi...

  • プロジェクトそのものとは別に、もっと多くのものがドメインに .wtf 拡張子 を使えば、世界はより良くなると固く信じている

  • これは 代数的効果 の弱い形のように聞こえるが、こういう言語や、それで何ができるのかを見るのはやはり面白い

    • 代数的効果 を理解できたことはないが、Hurl のドキュメントは理解できる
      代数的効果が基本的に Hurl の toss キーワードのようなものなら、どういう点で toss より強力なのか気になる
  • 面白い思考実験だ
    自分は例外が本当に嫌いで、例外のない言語がほしい
    例外は現代の goto
    Maybe/OptionEffect/Result がある以上、例外を投げて、それがどこで処理されるかを頭の中で追跡しなければならない理由はほとんどない
    代数的効果がさらに人気を集め、すでに十分複雑なフロントエンド JS にまで影響を与えるのではないかと少し心配している。制御フローのために「例外」を投げる方式を奨励するからだ
    これがすべて非同期/同期の 色問題 を避けるためだというなら、個人的にはまったく見合わない

  • うわ、これは嫌だ。でも奇妙なことに、ほとんどエレガントな面もある
    頭の中でモデル化するのは非常に難しいが、それでもそう思う
    もう少し真面目に言うと、再開可能な例外と再開不可能な例外について、文法的に異なる catch 構文があってほしい。そうすれば、return が最も近い直前の例外の throw 側へ制御フローを戻すのかどうかという 文法上の曖昧さ がなくなる
    そして標準ライブラリは普通の値返し関数へ逃げるべきではない。自分で作ったものを食べて胃もたれしたからといって、食べない理由にはならない

    • その通り。ただ、別の案として、値が期待される場所で関数を呼ぶと、構文が自動的に catch するようにすることもできる
  • hurl されたものは捕まえられるが、toss されたものは捕まえられない、という理解で合っているのだろうか? 慣れるには少し時間がかかりそうだ
    それと、どれだけ Hurl を書いたら人に tosser と呼ばれ始めるのかも心配だ

  • Toss は興味深い言語構造のように聞こえる。スタックをたどって例外ハンドラを探し、そこから元の位置に戻って、何もなかったかのように実行を再開する
    この構造なら、ランタイムで 追加の動作を注入 できそうだ
    普通のオブジェクト指向コードではサービスコンストラクタを通じて依存性注入をするが、toss は「toss ハンドラ」でそれを可能にするものなのか?

    • Koka を見ればよい。代数的効果システムを持つ「本物の」言語だ
      https://koka-lang.github.io/koka/doc/book.html#why-handlers
    • Common Lisp の 条件システム とかなり似ている
      詳しくは知らないが、こういう形でランタイムに動作を注入できることは知っている
    • VB の Resume Next に似ている