thread_localメモ
自分用覚書、thread_local!で定義したstatic変数はスレッド毎に LocalKeyという構造体でwrapされる。各スレッド変数はそれぞれ外側に不変である、可変参照をしたいならRefCellを被せたりする。
use std::cell::RefCell; thread_local! { static X: RefCell<Vec<usize>> = RefCell::new(vec![]); } fn main() { X.with(|v| { println!("initial {:?}", v.borrow()); }); let j = std::thread::spawn(move || { X.with(|v| { v.borrow_mut().push(1000); println!("other thread {:?}", v.borrow()); }); }); j.join().unwrap(); X.with(|v| { println!("after other thread {:?}", v.borrow()); v.borrow_mut().push(1024); }); main_other_fn(); } fn main_other_fn() { X.with(|v| { println!("main_other_fn {:?}", v.borrow()); }); }
initial
other thread [1000]
after other thread
main_other_fn [1024]
SEKIROトロコンした
こんにちは、id:Krouton です。初任給でゲーミングPCを買ったんですけど本当に光るんですね、感動しました。
それはそれとしてこのPCでSEKIROをトロコンしたのでエントリ書きます。Discordで友達にGo Liveで配信しながらやってました。途中から社会人のくせに頻度高すぎて誰も来なくなったのは内緒。
初見はWikiなど禁止、ただし動画勢の友人達ががヒカルの碁のサイのように助言をしてきたりはありましたが。 2週目からはWiki解禁して最低限のボス+気分で中ボスだったので効率重視でやってました。
TL;DR
未トロコン勢
弦ちゃん倒せたらトロコンできるからそこまで頑張って
以下雑に語る
思い出が残ってるところだけ、ネタバレありなので注意されたい。
自作言語の構文を考えるのがめんどくさいそこのアナタ、Rustのマクロで楽してもいいわよ?
最近 とっくんのYouTubeチャンネル - YouTube さんの再度ハマり言語野が支配されてます、id:Krouton です。
事の発端
頭の中の大蛇丸が「今日はexpression-orientedな言語を作っていくことにするわね」「構文を考えるのがめんどくさいそこのアナタ、AST設計からスタートしても良くてよ?」って言ってくる
— 初診15分 (@Krout0n) 2020年5月7日
つまり「言語を作りたいけど具象構文考えるのめんどくせ〜〜!!!!」「パーサジェネレータ使うにしてもそれすら書き下すのもめんどくせ〜〜!!!!!」って時ありますよね?(あってくれ)
そんなアナタのためにS式でASTを表現するのをオススメします。Rustが書きたかったのでそうしましたが、他のマクロがサポートされてる言語なら大体できそう?
TL;DR と まとめ
- (1 + 2) + (3 + 4) を表現するのに
BinOP( Box::new(BinOP(Box::new(Number(1)), Add, Box::new(Number(2)))), Add, Box::new(BinOP(Box::new(Number(3)), Add, Box::new(Number(4)))), )
から
ast!((+ (+ 1 2) (+ 3 4)))
という風にS式で表現できるようになる。Box::newを手書きするのから解放されるようになる。
本編
type AST = Expression; #[derive(Debug, PartialEq)] pub enum Expression { Number(usize), Ident(String), } use Expression::*; impl From<usize> for Expression { fn from(n: usize) -> Self { Number(n) } } impl<'a> From<&'a str> for Expression { fn from(s: &'a str) -> Expression { Ident(s.to_string()) } } macro_rules! ast { ($i:ident) => { Expression::from(stringify!($i)) }; ($e:expr) => { Expression::from($e) }; } fn main() { dbg!(ast!(2)); // Number(2) dbg!(ast!(id)); // Ident("id") }
ここはFromを使ってるだけで特に難しいところはありませんね。ASTとマクロを拡張して関数適用(Apply)を考えてみましょう。
#[derive(Debug, PartialEq)] pub enum Expression { // 略 Apply { fn_lit: Box<Expression>, args: Vec<Expression>, }, } macro_rules! ast { (($fn:tt $( $arg:tt )*)) => { Apply { fn_lit: Box::new(ast!($fn)), args: vec![$( ast!($arg), )*] } }; // 略 ($e:expr) => { Expression::from($e) }; // exprより後にしないと1 や 2が全てIdentになるので最後に置く ($t:tt) => { Expression::from(stringify!($t)) } } ast!((print 1 2)); // Apply { fn_lit: Ident("print"), args: [Number(1), Number(2)] } ast!((+ 1 2)); // Apply { fn_lit: Ident("+"), args: [Number(1), Number(2)] }
ミソとしては四則演算を関数適用として、stringify!で+などの演算子をIdentとして解釈する部分です。これのおかげで、四則演算用のマクロのルールを定義せずに表現できるようになりました。
あとは好きな風にASTを拡張して好きなS式で表現しましょう!
拡張したgist gist.github.com
Special Thanks
- S-expression in Rust macro_rules - Stack Overflow *2 に答えていただいたDenisKolodinさん
- この場を借りて感謝を申し上げます。
- とっくんさん
*1: コンパイラのミドルエンドって滅多に使わない言葉らしいってWikipedia先生が言ってた コンパイラ - Wikipedia
*2: 質問者は私です
Goの[]byte -> stringへのcastってshrinkするんですか?
珍しく技術系の投稿をします(ただし疑問、忘備録
tooEnoughBuf := make([]byte, tooEnoughSize) Write1(tooEnoughBuf, src) string(tooEnoughBuf) == string(src) // false
をしたい時のbufの長さをshrinkする方法を考えています。
なぜこの等価判定がfalseになるかというと
len(tooEnoughBuf) == len(src)
がfalseになるからですね。
func shrinkString(s string) string { var eos byte buf := make([]byte, 0) for _, b := range []byte(s) { if b == eos { break } buf = append(buf, b) } return string(buf) }
のような実装を与えてあげればいいのだろうか・・・?わからない・・・
株式会社はてなに入社しました
id:Krouton です。株式会社はてなに新卒入社しました。
本日からWebアプリケーションエンジニアです。
株式会社はてなに入社しました - hitode909の日記
所属してる会社は隠そうと思いましたが、GitHubのOrganizationを見れば分かってしまうし隠すのもなんか嫌なのでエントリにすることにしました。試用期間中にリストラされないことを祈っています。
されたら誰か誘ってください。とりあえずがんばります。
五カ年計画(後付)した電気通信大学を卒業しました
こんばんは。3/31で無事卒業できたので電通大卒業エントリを書こうと思います。今は無き情報理工学部の先端工学基礎課程(以下、K課程)に所属していました。
動機
1年前期(2015)
Twitterで気が合いそうなオタクを探しながら授業を受ける、バイトをしないといけなかったので授業中に探したりするも1ヶ月ぐらい連続で落ち続ける。*2
プログラミングに興味があったので学内のサークルに入るも、経験がなく何も分からないし、ノートPC持ってなかったので手を動かせずに消える。
Vim vs Emacsみたいなことをしていてたくさん会話してて面白そうだけど一切わからんしここは俺のためのところじゃないなぁと幽霊になる。
結局ファミマでバイトをしてました。初の落単を経験する。
1年後期
幽霊してたサークルの同学年のオタクが技術系バイトをしてることを知る。当人に「最低賃金で立ちっぱのバイトつらそう」と言われ、悔しくなったのでバイト代でMBPを買った。
- 作者:MMGames
- 発売日: 2011/06/24
- メディア: 単行本
2年前期(2016)
SIerっぽいとこがバイト先になった。d3.jsでグラフ書いたり、出たばっかのSwift3を使ってiOSアプリのプロトタイプ版みたいなのを一人で作ったりしてた。JSもSwiftも何もわからなかった。
2年後期
学生ベンチャー企業と掛け持ちした。JSとAWSでサーバサイドをやってた。心理的安全性がありえん低く辛かったのに加え、年明けに高1から付き合ってた彼女に振られて心が壊れる。電車の中で涙が出てきたり、途中下車して号泣したりしてた日もあった。
3年前期(2017)
心が壊れてました。土曜1限起きれなくて落単、これが留年のきっかけになる。あとインターンシップが必修であったので、夏休みに2週間フルタイムで行ってた。そこではCircleCIとシェルをにらめっこしてた。
3年後期
初めて心療内科に行く。行くまでは自分の精神も管理できないどうしようもなくダメな人間だと思っていたけど、見方が変わった。SICPを少し読んだ。インターン先がバイト先になった。ScalaとTypeScriptを雰囲気で書いてた。それまで静的型付けがない言語を触っていたが、型があるといいな〜とか思い始める。この辺から言語に対する興味が強くなった。
4年前期(2018)
セキュキャンのCコンパイラゼミに通る。自分より圧倒的にすごい人達に圧倒される。謙虚になった。セルフコンパイルはできてないし未だにずっと「やろうやろう」考えている。本当に。
knium.hatenadiary.com
K課程は4年前期まで必修が誰でもあるカリキュラムになっているのだが、3年前期の落単科目が突然時間割変更して4年の必修科目に衝突する。留年確定。
4年後期
2科目ぐらいしかなかったのでほぼ引きこもりみたいになってた。わからん。記憶がない。科目はすべて必修だが、出席を取らなかったのでほとんど出た記憶がない。テスト前に教えてくれた友人達に圧倒的感謝。
5年前期
タスクを複数同時に持つと死ぬことを学ぶ。複数持ってたタスクは全部投げ出した。院試を受けたけど全然ダメだった。単位取りきった。就活もした。
5年後期
休学、インターンとバイト、卒業
振り返ってみて
授業の記憶ない・・・。通学に往復3時間かかるとそれだけで起きてる時間の1/5は持ってかれるのでできるだけ近くに住んだほうがいい、でも自分みたいな人間は一人暮らししたら破滅が見えるので難しいね。
4年前期に留年が確定してなかったらセキュキャンに行くことはなかったと思う。*4
GPAが低い自分が言うのもアレですが、情報やプログラミング、CS系は努力した分だけ報われるのがよく分かる分野だと思う。たぶん真の意味で技術は好きじゃないのかもしれないけど、生きる分にはそれでもいいかなってなってきた。何回も挫折したし、やめたくなったけど何とか辞めずに続けたし、これからも何とか続けて生きていたいなぁと思います。
Haskellやる
いちいちTokenizerやParserをライブラリを使わずに書くのはダルい。だからパーサジェネレータ(lex/yacc)を使ったりするものだが、Rustで書こうとするとパーサコンビネータである
github.com
が強いっぽい。nomを見てみたら何もわからん状態になったので影響を強く受けたっぽい
github.com
のtutorialから雰囲気でやってみようと思ったけどこれまた何もわからない。
なので、手元にすごいH本もあるしやってみようと思う。