はじめに
元ネタ:Javaで湯婆婆を実装してみる(@Nemesis 様)
この記事をきっかけに色々なプログラミング言語で湯婆婆を実装するのが流行ってるらしいので便乗します。
D言語とは?
ご存じない方の為に軽く説明します。
D言語(D Programming Language, dlang)はWalter Bright氏によって開発された、C言語の流れを汲みつつもモダンな機能を取り入れ続ける超イカしたプログラミング言語です。
公式ホームページ:D Programming Language
環境
この記事のコードは以下のバージョンでの動作を確認しています。
- dmd : DMD64 D Compiler v2.094.0
- rdmd : build 20200922
実行環境をお持ちでない方へ
D言語を貴方のコンピュータに導入することは人生最良の行動です。
こちらの記事を参考に今すぐインストール!
ソースコード
その1
本家の処理をそのままなぞったものが次のコードです。
import std;
//import std.stdio : readln, writeln;
//import std.string : chomp;
//import std.random : Mt19937, unpredictableSeed, uniform;
//import std.conv : to;
void main(){
writeln("契約書だよ。そこに名前を書きな。");
dstring name = chomp(readln!dstring);
writeln("フン。", name, "というのかい。贅沢な名だねぇ。");
Mt19937 gen;
gen.seed(unpredictableSeed);
ulong newindex = uniform(0, name.length, gen);
dchar newname = to!(dchar[])(name)[newindex];
writeln("今からお前の名前は", newname, "だ。いいかい、", newname, "だよ。分かったら返事をするんだ、", newname, "!!");
}
基本的な文法はC++やJavaに近いものになっています。エントリーポイントはvoid main()
です。import std
により標準ライブラリを一括でインポートしていますが、コメントアウト部分のようにモジュールごと、関数ごとのインポートも可能です。
func!T
は、型T
によるfunc
のテンプレートを意味しています。
例えばto!(dchar[])(name)
は、引数name
のキャスト先の型をテンプレートによってdchar[]
と指定しています。
その2
import std;
void main(){
writeln("契約書だよ。そこに名前を書きな。");
auto name = readln!dstring.chomp;
writeln("フン。", name, "というのかい。贅沢な名だねぇ。");
Mt19937 gen;
gen.seed(unpredictableSeed);
auto newname = name.choice(gen);
writeln("今からお前の名前は", newname, "だ。いいかい、", newname, "だよ。分かったら返事をするんだ、", newname, "!!");
}
少々書き直しました。auto
は型推論に使用するキーワードです。
D言語はUFCSという機能を採用しており、これによりメンバ関係等にない処理をメソッドチェーン的に記述することが出来ます。
例えばa.b.c.d
はd(c(b(a)))
の、name.choice(gen)
はchoice(name, gen)
のシュガーシンタックスになっています。
その3
おまけ。
import std;
void main(){
writeln("契約書だよ。そこに名前を書きな。");
(name){
writeln("フン。", name, "というのかい。贅沢な名だねぇ。");
(newname =>
writeln("今からお前の名前は", newname, "だ。いいかい、", newname, "だよ。分かったら返事をするんだ、", newname, "!!")
)((gen){
gen.seed(unpredictableSeed);
return name.choice(gen);
}(Mt19937.init));
}(readln!dstring.chomp);
}
参考:D言語における関数リテラルの記法は以下の通りです。
//普通の関数リテラル
(Type x){
//hoge
return fuga;
};
//例
auto square = (real x){
return x^^2;
};
//ラムダ式
(Type x) => hoge;
//例
auto square = (real x) => x^^2;
実行
rdmdは、D言語の公式コンパイラdmdによるスクリプト風実行ツールです。
$ rdmd yubaba.d
契約書だよ。そこに名前を書きな。
千尋
フン。千尋というのかい。贅沢な名だねぇ。
今からお前の名前は千だ。いいかい、千だよ。分かったら返事をするんだ、千!!
名前を空白のまま入力した場合、仕様通り湯婆婆はクラッシュします。
$ rdmd yubaba.d
契約書だよ。そこに名前を書きな。
フン。というのかい。贅沢な名だねぇ。
core.exception.AssertError@/home/jj1lis/dlang/dmd-2.094.0/linux/bin64/../../src/phobos/std/random.d(2705): std.random.choice!(dstring, MersenneTwisterEngine!(uint, 32LU, 624LU, 397LU, 31LU, 2567483615u, 11LU, 4294967295u, 7LU, 2636928640u, 15LU, 4022730752u, 18LU, 1812433253u)).choice(ref dstring range, ref MersenneTwisterEngine!(uint, 32LU, 624LU, 397LU, 31LU, 2567483615u, 11LU, 4294967295u, 7LU, 2636928640u, 15LU, 4022730752u, 18LU, 1812433253u) urng) ref: invalid Range supplied. Range cannot be empty
----------------
??:? _d_assert_msg [0x5589c8b818ba]
??:? pure ref @safe immutable(dchar) std.random.choice!(immutable(dchar)[], std.random.MersenneTwisterEngine!(uint, 32uL, 624uL, 397uL, 31uL, 2567483615u, 11uL, 4294967295u, 7uL, 2636928640u, 15uL, 4022730752u, 18uL, 1812433253u).MersenneTwisterEngine).choice(ref immutable(dchar)[], ref std.random.MersenneTwisterEngine!(uint, 32uL, 624uL, 397uL, 31uL, 2567483615u, 11uL, 4294967295u, 7uL, 2636928640u, 15uL, 4022730752u, 18uL, 1812433253u).MersenneTwisterEngine) [0x5589c8b7f442]
??:? _Dmain [0x5589c8b7e03e]
D言語の実行時エラー処理は非常に優秀で、どこで例外が発生したか長すぎてむしろ見づらい一目瞭然です。