リスト風の Rust

2026/05/10 6:46

リスト風の Rust

RSS: https://news.ycombinator.com/rss

要約

Japanese Translation:

RLisp は、Rust のパフォーマンスと安全性を享受しつつ、LISP の S 式構文の可読性をもたらすための独自のソリューションを提供します。

rustc
を介して直接ネイティブバイナリにコンパイルされるため、ランタイム環境やガーベジコレクターの使用は不要となり、所有権、借用、ライフタイム、ジェネリック、トレイト、パターンマッチングなど、Rust のコア機能を完全にサポートしています。インストールは簡単で、GitHub リポジトリをクローン(
git clone https://github.com/ThatXliner/rlisp.git
)し、
cargo install --path .
を実行するだけです。このツールには、LISP ファイルを変数化するためのコマンドラインユーティリティ(
rlisp compile
)、ビルド(
rlisp build
)、実行(
rlisp run
)が組み込まれています。開発者は非対応の機能のために生の Rust コードをそのまま使用するために
(rust "...")
フォームを採用でき、マクロは Runt のプロシージャルマクロに依存せず、
(quasiquote)
(unquote)
(unquote-splicing)
などの慣れ親しんだ LISP 構造体を利用してコンパイル時の変換を実行できます。
&rest
でキャプチャされた可変引数は
unquote-splicing
を使用してマクロ出力に平坦化できます。言語は
(while ...)
(loop ...)
(for ...)
などを含む標準制御構造と解像度付きイテレータをサポートし、型注釈を受け取る typed クロージャ(例:
((x i32) (y i32)) -> i32
)および引数を明示的に移動するための
move
キーワードを提供します。可視性修飾子は Rust の慣習に従います(
pub
pub(crate)
pub(super)
)。このプロジェクトは MIT ライセンスでリリースされており、マクロ開発を簡素化し、バランスの取れた括弧の構造的編集を可能にし、Rust セマンティクスを低い構文障壁で提供することを目的としています。

本文

rlisp: RUST 言語のセマンティクスと LISP 構文

rlispとは、Rust のセマンティクス(所有権、借用、ライフタイム、ジェネリック型、トレイト、パターンマッチなど)をそのまま維持しつつ、LISP の構文(S-式)を採用したトランスパイラです。S-式を読み込み、中間表現として Rust コード(

.rs
)を生成し、最終的にバイナリへコンパイルします。

特徴:

  • ランタイムなし、GC 不要: スタンダードな Rust の動作(コンパイラ
    rustc
    が行う型検査、借用検査、最適化など)のみを利用します。rlisp は構文変換だけの役割を担います。
  • セマンティックギャップゼロ: Rust が持つあらゆる機能が S-式で自然に表現可能です。

インストール

git clone https://github.com/ThatXliner/rlisp.git
cd rlisp
cargo install --path .

使い方

  • rlisp compile file.lisp

    ファイルをトランスパイルし、
    file.rs
    を生成します。
  • rlisp build file.lisp

    トランスパイルして、
    rustc
    でコンパイルします。
  • rlisp run file.lisp

    トランスパイル、コンパイル、実行を一気に行います。

構文マッピング

LISPRust
(fn add ((x i32) (y i32)) i32 (+ x y))
fn add(x: i32, y: i32) -> i32 { (x + y) }
(let x i32 42)
let x: i32 = 42;
(struct Point (x f64) (y f64))
struct Point { x: f64, y: f64 }
(enum Option (T) (Some T) None)
enum Option<T> { Some(T), None }
(match val ((Some x) (handle x)) (None ()))
match val { Some(x) => { handle(x) }, None => { } }
(if (> x 0) (println! "yes") (println! "no"))
if (x > 0) { println!("yes") } else { println!("no") }
(impl Point (fn new (...) ...))
impl Point { fn new(...) ... }
(trait Display (fn fmt (...) Result))
trait Display { fn fmt(...) -> Result; }
(new Point (x 1.0) (y 2.0))
Point { x: 1.0, y: 2.0 }
(. obj field)
obj.field
(. obj method arg)
obj.method(arg)
([] arr 0)
arr[0]
(foo! args)
foo!(args)
(println! "{}" x)
println!("{}", x)
(loop (println! "tick"))
loop { println!("tick") }
(while (> x 0) (-= x 1))
while x > 0 { x -= 1 }
(for x in 0..10 (println! "{}" x))
for x in 0..10 { println!("{}", x) }
(lambda (x y) (+ x y))
|x, y| { x + y }
(pub fn foo () i32 42)
pub fn foo() -> i32 { 42 }
(pub (crate) mod m (fn f () () ()))
pub(crate) mod m { fn f() {} }
(use std::collections::HashMap)
use std::collections::HashMap;
(const MAX usize 1024)
const MAX: usize = 1024;
(rust "let x: i32 = 42; x")
let x: i32 = 42; x

注釈:

  • 二項演算子(
    +
    ,
    -
    ,
    *
    ,
    /
    ,
    ==
    ,
    !=
    ,
    <
    ,
    >
    ,
    &&
    など)はインフィックス表記に変換されます。例えば、
    (+) a b
    (a + b)
    へと展開します。

マクロ

rlisp のマクロは、コンパイル時の S-式トランスフォーマーです。

proc_macro
クレート、トークンストリーミング、syn/quote などの複雑な仕組みは使用せず、マクロを「S-式から S-式へ変換する関数」としてのみ考えます。

マクロ本体では、LISP から由来する以下の 3 つの特殊形式を利用します:

形式意味
(quasiquote template)
「このテンプレートを引用しつつも、内部にあるアンクォートを許可する」——タグ付きテンプレートリテラルのような挙動です。
(unquote name)
「ここで name の値を挿入する」——テンプレート上の穴(ホール)です。
(unquote-splicing name)
「リスト name を surrounding list にスパイスする(埋め込む)」——複数の形式を挿入するために使用します。

quasiquote
は、「アンクォートを除いたこの正確な S-式を返す」と捉えれば良いでしょう。これをなくすと、各括弧を
list
cons
で手動で構築しなければなりません。

;; 条件が満たされた場合、本体を実行する when マクロの定義
(defmacro when (condition &rest body)
  (quasiquote (if (unquote condition) (do (unquote-splicing body)))))

;; マクロ展開例:
;;   (when (> x 10) (print "big") (print "huge"))
;; → (if (> x 10) (do (print "big") (print "huge")))
;; → if x > 10 { print("big"); print("huge") }

(defmacro double (x)
  (quasiquote (+ (unquote x) (unquote x))))

;; (double 21) → (+ 21 21) → 21 + 21

(fn main () ()
  (let x 21)
  (println! "Double: {}" (double x))
  (when (> x 10)
    (println! "x is greater than 10")
    (println! "this too")))

&rest
は残りのすべての引数をリストにキャプチャし、
unquote-splicing
はそのリストを surrounding 形式へフラット化(展開)します。これにより可変引数のマクロが動作します。

ループ処理

(while (> x 0)
  (println! "{}" x)
  (-= x 1))

(loop (println! "tick"))

(for x in 0..10
  (println! "{}" x))

;; デストラクチャリング付きの for ループ
(for (i val) in (. v iter) enumerate
  (println! "{}: {}" i val))

クロージャ

;; タイプなし
(let add (lambda (x y) (+ x y)))

;; リターン型を付与したtypedクロージャ
(let mul (lambda ((x i32) (y i32)) i32 (* x y)))

;; 所有権を持つクロージャの生成
(let s "hello")
(let greet (lambda move () (println! "{}" s)))

モジュール、可視性、インポート

(pub fn public_api () i32 42)
(pub (crate) fn internal () i32 0)       ;; pub(crate)
(pub (super) fn parent_visible () i32 1) ;; pub(super)

(pub struct Config
  (pub host String)                        ;; パブリックなフィールド
  (port u16))                              ;; プライベートなフィールド

(pub mod utils                            ;; インラインモジュール
  (pub fn helper () i32 1)
  (fn private () i32 0))

(mod external_lib)                        ;; 外部モジュールの宣言

(use std::collections::HashMap)
(use std::io::{self,Write,Read})
(use std::fmt::Display as Fmt)

インライン Rust

rlisp がネイティブで表現できないことは、

(rust "...")
を使って生の Rust コードにドロップインできます。文字列は LISP のエスケープシーケンスを反転させた状態で生成された
.rs
ファイルへそのまま出力されます(verbatim)。

(fn raw_example () i32
  (rust "let x: i32 = 42; x * 2"))

(fn main () ()
  (rust "let message: &str = \"from raw Rust\";")
  (println! "{}" (rust "message")))

なぜ作るのか?(Why)

主に趣味として、構文を取り払いながらセマンティクスだけを維持した「Rust の姿」を探索するためですが、実用的な側面もあります:

  1. マクロが簡素化される。 LISP では、マクロはコンパイル時に S-式を受け取り S-式を返す単純な関数であり、トークンストリーミングや
    proc_macro
    の儀礼なしで動作します。これは LISP が Rust に持ち寄った「キラー特徴」です。
  2. 構造化編集。 S-式はスリップ(全体読み込み)、バフ(全体書き出し)、転置(行列転換)、ラップ(ネスト)といったエディタツールによる操作に対して非常に扱いやすく、すべての操作が構築によってバランスが取れています。
  3. 均質な構文。 表現式、ステートメント、型、パターンに区別がありません。すべて S-式です。
    match
    の腕や関数のシグネチャには、すでに知っている構文が使われています。

ライセンス

MIT

同じ日のほかのニュース

一覧に戻る →

2026/05/09 21:00

スイス・インターネット・アーカイブ

## Japanese Translation: インターネット・アーカイブは、デジタル保存とすべての知識への普遍的アクセスというミッションを設立者ブルースター・カールが 30 年前に定めた、独立した非営利財団としてスイスのセント・ガレンに本部を置く「Internet Archive Switzerland」を立ち上げました。このハブは、カナダやヨーロッパなどを含むグローバルネットワーク内で活動し、セント・ガレンに千年以上の学術的アーカイビングとイノベーションの伝統を持つことを活用して、レジリエントな地域図書館を創出します。初期の取り組みでは、危機にあるグローバルなアーカイブを保存すること、および現在の生成 AI の波に関連するデジタルコンテンツを収集することに注力します。重要なパートナーシップとして、ダミアン・ボース教授を率いるセント・ガレン大学工学部のコンピューターサイエンス学科との連携により、急速に進化する AI モデル向けの基準を確立する専門的な「Gen AI Archive」を設立します。これらの取り組みはさらに発展し、2026 年 11 月にパリで開催予定のユネスコ会議において、危機にあるアーカイブに対する保護方法について議論される予定です。実行責任者であるローマン・グリースフェルダー氏は、セント・ガレンが文化遺産に関して「安定性とイノベーションは両輪」と述べ、ユニークに安定性とイノベーションのバランスを維持していると指摘します。新しい財団は、より広範なグローバル使命に奉仕する地元のデジタル歴史保存にとって強力な先例を設定します。詳細は https://internetarchive.ch/ でアクセス可能です。 ## Text to translate: The Internet Archive has launched Internet Archive Switzerland, a new independent non-profit foundation based in St. Gallen dedicated to digital preservation and universal access to all knowledge—a mission established by founder Brewster Kahle 30 years ago. Operating within a global network that includes Internet Archive Canada and Europe, this hub leverages St. Gallen's thousand-year tradition of scholarly archiving and innovation to create a resilient regional library. Initial work will focus on saving endangered global archives and collecting digital content related to the current generative AI wave. A key partnership with the University of St. Gallen's School of Computer Science, led by Professor Damian Borth, will establish a specialized Gen AI Archive to set standards for rapidly evolving AI models. These efforts will be further explored at a UNESCO conference in November 2026 in Paris regarding protection methods for endangered archives. Executive Director Roman Griesfelder notes that St. Gallen uniquely balances stability with innovation, stating, "stability and innovation go hand in hand" regarding cultural heritage. The new foundation sets a powerful precedent for local digital history preservation serving a broader global mission, accessible at https://internetarchive.ch/.

2026/05/10 2:52

Show HN: Go で作成した、Clojure に似た言語を公開します。起動までの時間はわずか 7 ミリ秒です。

## Japanese Translation: Let-go は、Clojure に類似する言語のために設計されたバイトコードコンパイラおよび仮想マシンであり、同ファミリー内で最小で最も起動が速い選択肢を目指しています。コードを外部インフラストラクチャなしで動作するスタンドアロンのバイナリまたは WebAssembly アプリケーションに直接コンパイルします。主要なパフォーマンス指標には、約 10MB のバイナリサイズ、約 6-7ms のコールドスタート、低いアイドルメモリ使用量(約 14MB)が含まれ、これにより Babashka、GraalVM native、Joker、標準的な JVM 環境と比較して著しく小さく高速化しています。 このツールは、`core`、`core.async`、HTTP、JSON などのほぼすべてのコア Clojure ライブラリ(マクロ、プロトコル、トランスデューサー、永続データ構造など)をサポートし、標準的な `clojure-test-suite` の 95.4% を通過する強力な互換性を提供します。`core.async` チャンネル、HTTP サーバー、JSON/Transit、IO、およびバイナリプロトコル経由の Babashka pod の読み込み(データベース、AWS、Docker など)を含む「ボックスセット」機能をサポートしています。高度な機能としては、Go との相互運用性があり、Go アプリケーションへの埋め込みをサポートし、機能マッピングと双方向の呼び出しを可能にします。 展開オプションは柔軟です:ユーザーは Homebrew または Go モジュールを使用して自己完結型のバイナリを作成したり、ターミナルエミュレーションを含むブラウザ実行のための WebAssembly にコンパイルしたり、Emacs、VS Code、Neovim などのリッチなエディタサポートのための nREPL サーバーを利用できます。非常に効率的ですが、標準的な Clojure/Java ランタイムに見られる特定の機能(Refs/STM は atoms+channels で置き換えられ、Spec、`deftype`、読み込みタグ付きリテラル `#inst` など)は除外されています。 ## Text to translate: ## Summary: Let-go is a bytecode compiler and virtual machine for a language resembling Clojure, designed to be the smallest and fastest-starting option in the family. It compiles code directly into standalone binaries or WebAssembly applications that require no external infrastructure to run. Key performance metrics include a ~10MB binary with approximately 6-7ms cold starts and low idle memory usage (~14MB), making it significantly smaller and faster than alternatives like Babashka, GraalVM native, Joker, and standard JVM environments. The tool offers robust compatibility by supporting nearly all core Clojure libraries (including `core`, `core.async`, HTTP, JSON) and features like macros, protocols, transducers, and persistent data structures, passing 95.4% of the standard `clojure-test-suite`. It enables "batteries included" functionality with support for `core.async` channels, HTTP servers, JSON/Transit, IO, and Babashka pod loading (e.g., databases, AWS, Docker) over a binary protocol. Advanced features include Go interop, allowing embedding in Go apps with feature mapping and bidirectional calls. Deployment options are flexible: users can create self-contained binaries via Homebrew or Go modules, compile to WebAssembly for browser execution with terminal emulation, and utilize an nREPL server for rich editor support (Emacs, VS Code, Neovim). While highly efficient, it excludes certain features found in standard Clojure/Java runtimes, such as Refs/STM (replaced by atoms+channels), Spec, `deftype`, and reader tagged literals like `#inst`.

2026/05/10 2:30

Zed エディタ テーマビルダー

## Japanese Translation: Summary: `MeetingScheduler` は、標準のスケジューリングロジックの他にユーモアを伴う制約を強制するために設計された React コンポーネントです。`useState`、`useEffect`、`useCallback` などのフックを用いて構築されており、ID、タイトル(デフォルトは"Meetings about meetings")、出席者リスト、スナックの用意状況、会議が本当に時間通りに始まるかを示す `Meeting` インターフェースを備えています。このコンポーネントは、"scheduled"、"running-late"、"cancelled"、または "eternal" を含むステータスをサポートします。出席者数は厳密に検証され、テキストの表現における「maxAttendees」のデフォルト値 100 が検証ロジックにより上書きされているにもかかわらず、リストでは<50 と指定されています(1 名から 49 名の間)。また、`MEETING_EXCUSES` アレイを通じて「Sorry, I was on mute」や"Per my last email..."のような事前入力された言い訳を提供します。UI は絵文字付きのヘッダーを表示し、30 分から全日までの期間選択を許可し、`crypto.randomUUID()` を使用してユニークな ID を生成するとともにデフォルトでスナックが必要であることを要求します。重要な安全機構として、60 秒ごとに `sanityRef` を減少させるインターバルエフェクトがあり、これがゼロになるまで持続します。さらに、ユーザーが去ろうとする際にトリガーされる"escape attempt"コールバックも備わっています。