RustでOperator Overloadを利用したDSLを作ってみる

気が付いたら2025年が終わってました。今年の抱負とか考える前に仕事が始まったので、今年もいきあたりばったりに行きていければと思います。 最近Rustで細々と格闘しているんですが、ちょっとやってみたいことがあってやってみたらできたので、小ネタとして残しておこうかと思います。 やりたいこと 諸事情で、代数式をstructとして管理することをしています。毎度ですが、なんでそういうことをしようとしているのか?は聞いてはなりません。 // こんなtraitを定義しておく trait Equation { // envは変数のhashmap fn evaluate(&self, env: &HashMap<String, f32>) -> f32; } こんなtraitを実装したものを考えたいです。なお実装は自明なので省きます。で、これを普通に実装すると、ちょっと複雑になっただけで大変なことになります。 // 3.2 + 3.4 let e = ArithmeticEquation::new(Add, ConstantEquation::new(3.2), ConstantEquation::new(3.4)) // 掛け算とかがnestすると大変なことになる これをなんとかある程度楽にしたい、というのがモチベーションです。 方法の検討 Rustだと、大きく3通りのやり方があると思います。 procedural macroを実装する lexer/parserを利用してparseを実装する operator overloadとstructを駆使して頑張る macroとoperator overloadはcompile時に、lexer/parserは動的になる感じです。最終的にはlexer/parserが必要になりそうなんですが、一旦は静的にできれば(テストを書いたりするときに)便利です。となると、macroかoperator overloadが選択肢になる感じですね。 lexer/parser自体を生成するmacroとかはあるようですが、そもそもparseするという行為自体が、compileした後の話になるので。 Operator overloadを検討してみる RustのOperator overloadは大変に強力である意味シンプルなのですが、 Scopingが困難 です。 KotlinとかのOperator overloadでは、interfaceの実装元とかで切り分けられたり、scoped functionを利用することで、DSL/operator overloadの利用範囲をscopingすることがるできます。 object Ops { operator fun invoke(f: Ops.() -> Unit) { f() } infix fun String.test(rhs: String): boolean {...} } // こんな感じで使える Ops { "hoge" test "foo" } // 外だと明示的なimportが必要。 翻ってRustのOperator overloadは、標準にある Add や Sub といったTraitを型に対して実装する・・・という形です。 ...

January 12, 2026 · derui

Kanzenという日本語入力の方式を再実装してみた Part.2

盆の前後が台風という、なかなかな感じですが、元気にやっていきたいところですね。 前回に引き続き、chokanについて書いていきます。今回は辞書で利用しているアルゴリズムと、実装方針について書いていきます。 ...

August 15, 2024 · derui

自分でかな配列を計算してみた

気づくとGWがおわっていました。何を言っているか(ry さて、今回は題名にもあるとおり、ようやく使えそうになったかな配列について書こうかなと思います。 ...

May 26, 2024 · derui

Rust + YewでTypeScript + Reactをリライトしてみた

あけましておめでとうございます。鏡開きギリギリなのでまだそう言っていいはず・・・。気付いたら転職して大体2年経過していたり、引越してから一年過ぎていたりして、時間の流れははえーなぁ、と思う日々です。 大体一ヶ月くらいセコセコとやって、年末年始も(珍しく)実家で作業していたりしたやつが、基本部分は動くようになったので、それについて書いてみます。 ...

January 10, 2022 · derui

Rust + YewでTypeScript + Reactをリライトしてみた

あけましておめでとうございます。鏡開きギリギリなのでまだそう言っていいはず・・・。気付いたら転職して大体2年経過していたり、引越してから一年過ぎていたりして、時間の流れははえーなぁ、と思う日々です。 大体一ヶ月くらいセコセコとやって、年末年始も(珍しく)実家で作業していたりしたやつが、基本部分は動くようになったので、それについて書いてみます。 <!–more–> きっかけ きっかけは単純で、色々見ていたときに、 yew というフレームワークを見つけたから、です。 https://yew.rs/ どういうものかというと、 Rust製 React.jsを強く指向したコンポーネントライブラリ 周辺にstate管理(だけじゃないけど後述)、ルーターなども整備していて、必要最小限は揃っている というものです。超荒く言うと、 Rustで全部やっちゃおうぜ というやつですね。js_of_ocamlとかBucklescriptとかで実際似たようなことをやっていた身としては馴染があります。あっていいのか。結論的には、いつもの やってみたかった駆動開発 です。 リポジトリ https://github.com/derui/simple-planning-poker/tree/yew すでにこのリポジトリが盛大な実験場となっているのは気にしないでください この記事の時点だと、必要最小限成立する程度の機能までしかできてません。一応道筋は見えているので、実装自体は簡単ではありますが。 構成 利用しているライブラリはCargo.tomlを見たらだいたいわかるようになっていますが、それ以外の構成も含めて、利用しているツールなど。 Rustは最新安定版 yarn v3 ずーっとv1使ってきましたが、アップグレードしてみました Webpack 5 wasm-pack + wasm-pack-plugin メインのprojectとサブprojectとして分離 ルートのCargo.tomlには、projectsの定義のみ入れています ライトなCleanArchitecture的思想 ただし、これはプロジェクト構成を失敗した感も・・・ yew-agent/yew-routerを利用してルーティングとか wasm-bindgen + gloo + wasm-bindgen-future Firebase(realtime database/auth)を利用 当然Rustから呼んでます TSな部分は、依存をglobalに展開 + Firebaseの初期化のみ という形になっています。ぶっちゃけ途中はテストも書かずにひたすら移植作業していたので、実際に動くのかどうか?は実際に動かしながら試してみた・・・というあんまりよくない形になっています。が、テスト書きながらだと多分この2倍かかった気がするので、とりあえずどういうものなのか?を確かめるという目的を達成するためにはこれでよかったかな、と。 yewでどうやって書くのか? Rustがどういうものか、とかは全部すっとばします。Rust公式に良質なドキュメントがあるのでそちらをどうぞ。また、初期セットアップも全部すっとばします。公式ドキュメントを見たほうが早いです。 超簡単なサンプルとしてはこんな感じになります。 #[derive(Properties, PartialEq)] pub struct Property { counter: u32, } #[function_component(Component)] pub fn component(props: &Property) -> Html { html! { <div><span> {"Counter: "} </span><span> {props.counter}</span></div> } } #[function_component(Main)] pub fn main() -> Html { let state = use_state(|| 0); let onclick = { let state = state.clone(); Callback::from(|_| state.set(*state + 1)) }; html! { <Component counter={*state} /> <button onclick={onclick}>{"Click"}</button> } } yewは、 struct component と functional component という二通りの実装が可能です。この辺もReactのClass ComponentとFunctional Componentとよく相似していますね。 ...

January 10, 2022 · derui

Rustで超簡単なツールを作ってみた

気付いたら8月です。猛暑というか酷暑というかですが、台風が来てくれると多少熱が持っていかれるので、多少は過ごしやすくなってくれるといいんですが。 少しは別のこともやらんとなぁ、ということで、久し振りにRustを使ってちゃんとしたツールというのを作ってみました。 <!–more–> 何を作ったのか https://github.com/derui/org-roam-protocol-installer こんなのを作りました。今、個人なナレッジの蓄積としてorg-roamを利用しています。org-modeには、org-protocolという、外部からorg-modeに対してcaptureを行わせることができる仕組みが存在しています。 org-roamにはこれを独自に拡張した、org-roam-protocolというものがあります。これを利用すると、webページとかをお手軽にorg-roamにcaptureする・・・ということができます。 が、リンク先のドキュメントを見てもらえばわかるのですが、ファイルを作ったりなんだりと、別段複雑ではないものの、多少手順が必要だったりして、これはこれでなぁ・・・みたいなことを考えました。特にmacOSがめんどくさい。 ということで、じゃあこれをインストールするだけのツールを作ればいいんでない?ということを思いつき、ついでにRustの勉強(実際には以前使っていたので復習)がてら、Rustで作ってみることにした、という次第です。 使ったcrate Cargo.tomlを見たらわかりますが、今回はきちんと?crateを利用しました。 clap CLIのフレームワーク。サブコマンドの定義とか色々可能 dirs HOMEとか特殊なディレクトリとかにアクセスするため tempfile 一時ファイルを適切に作成するため ソースは見てないけど、挙動的にdropすると削除されるようになってる quick-xml 高速な低レベルXMLライブラリ。Info.plistの編集で使ってます 常日頃OCamlをよく利用している側としては、一つの処理に対して色々なcrateがあってすげーなぁ、と思うと同時に、どれを選んだらいいのかわからない問題も起きがちだなぁ、というのはやっぱりありますね。 苦労した点 私はmacOSを個人では保有していないので、macOSでのインストール作業をどう自動化するか?を結構悩みました。 Script EditorをApplescriptで起動して保存させる・・・? ApplescriptをApplicationとして保存しなければならないのですが、そのためにはScript Editorしか使えなさそうに見えた そもそもApplescriptで↑ができる・・・? とか考えましたが、最終的には osacompile というコマンドの存在を知り、これでええやんってことになりました。このあたり、独自形式を突っ走るmacOSがめんどくさいですね・・・。 所有権とかは苦労していないの? Rustでよく言われる所有権とかborrow checkerですが、そこまで苦労はしませんでした。というか、普通にプログラムを作っていったら、一つの中で書きこみと読みこみを同時にやる、とか基本的にそこまでしないはずなので。 ライフタイムとかを考え始める = structにオブジェクトを含めるようになると、めんどくさくなるのが目に見えてますが、今回はそこまで必要なかったというのもあります どちらかというと、 File::open と File::create の違い(Cとか他の言語だと、大抵はopenに引数を付けてwriteとかappendとかにする)とか、traitを渡すためにはどうすればいいか、とかの方がよほど苦労しました・・・。 エラーメッセージが大分親切になっているので、そこまで困らなくなったように思います。 あらためてRustでよいなと思った点 Testが統合されている Rustはtest用のモジュールを、それぞれのモジュールに含めることができるので、かなり細かいテストまで作成できる、という点はやはりよい点ではあります。 ただ、これには負の点もあって、内部実装を細かくテストしすぎると、リファクタリングとかがめんどくさくなります(private methodをテストするのと同様のことができてしまうので)。 ポインタの心配がない Null dereferenceとかの心配が無いのはよいです。まぁ、その代わりにmutとかborrow checkerとかを確認しなければならない、ということでもあるんですが。 CとかC++とかで生ポインタを触る場合は、super powerを手にしているのと同じようなものなので、注意しなければならない、というのを思い返させてくれますね。 crateが豊富 上でも書きましたが、直近のえらい盛り上がりに比例して、crate数がものすごいことになっています。当然ながらそうなると玉石混交にもなるんですが、やりたいことに対してcrateが見つかるというのは気楽です。 OCamlとかだと、下手したら存在しないから自分で書く羽目になる、とか、メンテナンスが進んでいないやつしかない・・・とかにもなりえます。最近は少なくなってきましたが。 targetを変更してビルドしやすい OCamlでは結構めんどくさいので、これはうらやましい点ですね。まぁ、前提や設計された時代背景がそもそも違うので、単純に比較するとそれはそれで無知をさらけ出すことになりますが・・・。 解決できていない点 Linuxでは動作を確認できているんですが、macOSにおいては、Gatekeeperを突破する方法がいまいちわからず、ダウンロードしたものをそのまま利用することができない状態です。 正当な手段は、Apple Developer IDを取得してきちんと署名する、ということだと思うんですが・・・。 高い Macを保有していないし、macOS向けになにをするわけでもないのに年間$99も払えません プロセスが複雑になる とかなので、基本的には色んなところで配布されているCLIを参考にしてバイパスできるようにしようと思います。 ツールを作ることでの学習 久し振りに簡単なツールを作りきりましたが、やはり簡単でもいいので作りきるということは、個人的に進歩するなぁ、という実感があります。 ...

August 7, 2021 · derui