15
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

D言語Advent Calendar 2012

Day 3

"Hello, world!"の話

Last updated at Posted at 2012-12-02

本日は私、SHOOが某所に起稿した H.e.l.l.o. w.o.r.l.d! D について解説いたします。

まずはそのプログラムをご覧に入れましょう

import std.string, std.range, std.algorithm, std.conv, std.array;

struct D
{
    string msg;
    D opDispatch(string s)() @property
    {
        return typeof(return)(
            ((a, b)=>a.equal(b))(
                msg.retro().cycle().take(2),
                msg.chain(s).retro().take(2).array().retro())
                ? ((a, b)=>(
                    a.insertInPlace(msg.countUntil(b)+1, ", "), a.idup)
                  )(msg.dup, msg.retro().take(2).array().retro())~s
                : text(msg,s));
    }
    string d(T)() @property
    {
        return text(msg, T.stringof.toLower(), "! ", T.stringof);
    }
}
struct H
{
    static D opDispatch(string s)() @property { return D(typeof(this).stringof~s); }
}

pragma(msg, H.e.l.l.o. w.o.r.l.d! D);

void main() {}

"Hello, world!"はもう古い

過去の"Hello, world!"プログラムは

#include <stdio.h>
int main(int argc, const char *argv[])
{
	printf("Hello, world! C\n");
	return 0;
}

表示のために実行が必要

_人人人人人人_
> ダサい! <
 ̄^Y^Y^Y^Y^ ̄

D言語なら pragma(msg, ...) やCTFE、テンプレートメタプログラミングを使うことで

コンパイル時に任意の処理を行った結果の表示が可能

pragma(msg, H.e.l.l.o. w.o.r.l.d! D);

_人人人人人人人人人人人人人人_
> こんなにもスタイリッシュ <
 ̄^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^ ̄

経緯

○月×日 D言語が Dark Language だなんだとdisられる

夜、仕事から帰って、おもむろにTwitterをやった。
こいつら、Dark Languageだなんだときっとデマカセにちがいねェ。
俺たちをばかにしやがって。

○月△日 アンサイクロペディアの"Hello, world!"が壊れていることに気づく

今日、アンサイクロペディアの記事から昔の"Hello, world!"の世話を頼まれた。
皮をひんむいたJavaのような奴だ。
コードが通らないってんで、dmdに投げこんだら、奴ら、writelnのproperty文が通らなかったりDeprecationを引き出したり
喚いたあげくやっと死にやがる。

△月□日 UFCSの登場

今朝5時頃、宇宙服みてえなダブルクォーテーションを着た"Hello, world!"に突然たたき起こされて俺は興奮した。
なんでも、D言語に新機能の追加があったらしい。
コントリビューターの連中ときたら、夜も寝ないでコミットばかりやってるからこんな事になるんだ。

○月▽日 ダブルクォーテーションの削除を決意

昔からこのいまいましい宇宙服をつけたままなんで、背中がむれちまって妙にかゆい。
いらいらするんで、腹いせにあの"Hello, world!"のダブルクォーテーションを抜きにしてやった。
いい気味だ。

○月○日 UFCSとopDispatchの組み合わせ

あまりに背中がかゆいんで医務室にいったら、背中にでっけえopDispatchを貼られた。
それから、もう俺は宇宙服を着なくていいと医者がいった。
おかげで今夜はよく眠れそうだぜ。

○月◎日 セミコロンを使ったら負けかと思っている

朝起きたら、opDispatchだけでなくRangeにもUCFSができてやがった。
引用符の代わりにセミコロンがやけに煩いんで、足引きずって見に行ったら数が増えてる。
引用符を二個抜いたくらいで増えやがって。
おえら方に見つかったら大変だ。

○月◇日 特徴のある部分を使ってカンマ挿入位置を探す

昨日、このロジックから逃げ出そうとしたカンまが一つ、射さつされた、て はなしだ。
夜、からだ中 あついかゆい。
胸のはれ物 かきむしたら 肉がくさり落ちやがた。
いったいおれ どうな て

○月♡日 変数が必要ならラムダ式を使う

とくちょう みつ けた も とてもかゆい
変数 ひつようの、らむだ のしき つかう

○月⊿日 最後のエクスクラメーションはテンプレートを使って締めくくる

かゆい かゆい エクスクラメーションーきた
ひどいてんぷれなんて ころし
うまかっ です。
4

D言語
ウマー

解説(日本語OFFでお届けいたします)

import std.algorithm: equal;
unittest
{
	// UCFS, equal
	static assert("Hel".equal("Hel") == equal("Hel", "Hel"));
	
	// lambda syntax
	static assert( (a => a+1)(1) == 2 );
	static assert( (a => a+1)(1) == (delegate int(int a){return a+1;})(1) );
	static assert( (a => a+1)(1) == ((int a){return a+1;})(1) );
	static assert( (a => a+1)(1) == ((a){return a+1;})(1) );
}
import std.algorithm;
import std.algorithm: countUntil;
import std.range: retro, cycle, take, array, chain;
unittest
{
	// range compare
	static assert( __traits(compiles, "leH" == "leH"));
	static assert(!__traits(compiles, "Hel".retro() == "leH"));
	static assert( __traits(compiles, "Hel".retro().equal("leH")));
	static assert("Hel".retro().equal("leH"));
	
	// retro
	static assert("Hel".retro().equal("leH"));
	
	// take
	static assert("HelHelHelHelHelHelHel".take(7).equal("HelHelH"));
	
	// cycle + take
	static assert("Hel".cycle().take(7).equal("HelHelH"));
	
	// chain
	static assert("Hel".chain("l").equal("Hel" ~ "l"));
		
	// countUntil
	static assert("Hellowo".countUntil("ow") == "Hell".length);
	
	// /*take + retro*/ take + array + retro
	static assert(!__traits(compiles, "Hel".take(2).retro().equal("eH")));
	static assert("Hel".take(2).array().retro().equal("eH"));
}
import std.array: insertInPlace;
unittest
{
	/* insertInPlace ... (´・ω・`) */
	string msg = "owo";
	msg.insertInPlace(1, ", ");
	assert(msg == "o, wo");
}
import std.array;
unittest
{
	/* lambda + insertInPlace ... (`・ω・´) */
	static assert((a=>(a.insertInPlace(1, ", "), a))("owo".dup) == "o, wo");
}
import std.conv: text, toLower;
unittest
{
	// text
	static assert(text("a", 1) == "a1");
	
	// toLower
	static assert("AbCdE".toLower() == "abcde");
}
unittest
{
	struct H
	{
		// 型名 H に . 以降の文字列を連結
		static string opDispatch(string s)() @property
		{
			return typeof(this).stringof~s;
		}
	}
	static assert(H.e == "He");
}
unittest
{
	struct D {string msg;}
	struct H
	{
		// 型名 H に . 以降の文字列を連結したのを D 型にする
		static D opDispatch(string s)() @property
		{
			return D(typeof(this).stringof~s);
		}
	}
	static assert(H.e == D("He"));
}
unittest
{
	struct D
	{
		string msg;
		// . 以降の文字列を連結
		D opDispatch(string s)() @property
		{
			return typeof(return)(text(msg, s));
		}
	}
	struct H
	{
		static D opDispatch(string s)() @property { return D(typeof(this).stringof~s); }
	}
	static assert(H.e.l == D("He").l);
	static assert(D("He").l == D("Hel"));
	static assert(H.e.l.l.o.w.o.r.l.d == D("Helloworld"));
}
import std.algorithm, std.range;
unittest
{
	/+
	(a, b)=>a.equal(b))(
	        msg.retro().cycle().take(2),
	        msg.chain(s).retro().take(2).array().retro())
	+/
	// msgの最後2文字の逆順を得る
	auto left(string msg, string s)
	{
		return msg.retro().cycle().take(2);
	}
	static assert(equal(left("He","l"),        "eH"));
	static assert(equal(left("Hel","l"),       "le"));
	static assert(equal(left("Hell","o"),      "ll"));
	static assert(equal(left("Hello","w"),     "ol"));
	static assert(equal(left("Hellow","o"),    "wo"));
	static assert(equal(left("Hellowo","r"),   "ow"));
	static assert(equal(left("Hellowor","l"),  "ro"));
	static assert(equal(left("Helloworl","d"), "lr"));
	
	// msgとsを連結したものの最後2文字を得る
	auto right(string msg, string s)
	{
		return msg.chain(s).retro().take(2).array().retro();
	}
	static assert(equal(right("He","l"),        "el"));
	static assert(equal(right("Hel","l"),       "ll"));
	static assert(equal(right("Hell","o"),      "lo"));
	static assert(equal(right("Hello","w"),     "ow"));
	static assert(equal(right("Hellow","o"),    "wo"));
	static assert(equal(right("Hellowo","r"),   "or"));
	static assert(equal(right("Hellowor","l"),  "rl"));
	static assert(equal(right("Helloworl","d"), "ld"));
	
	// 要するに msgとsを連結した最後の3文字が回文になっているかを判定
	bool test(string msg, string s)
	{
		return equal(left(msg,s), right(msg,s));
	}
	static assert(!test("He","l"));
	static assert(!test("Hel","l"));
	static assert(!test("Hell","o"));
	static assert(!test("Hello","w"));
	static assert( test("Hellow","o")); // <<=========
	static assert(!test("Hellowo","r"));
	static assert(!test("Hellowor","l"));
	static assert(!test("Helloworl","d"));
}
import std.array, std.algorithm, std.range;
unittest
{
	/+
	((a, b)=>(
	  a.insertInPlace(msg.countUntil(b)+1, ", "), a.idup)
	)(msg.dup, msg.retro().take(2).array().retro())~s
	+/
	
	// msgのコピー(編集可能)を返す
	auto left(string msg, string s)
	{
		return msg.dup;
	}
	static assert(left("Hellow", "o") == "Hellow");
	
	// msgの最後2つを得る
	auto right(string msg, string s)
	{
		return msg.retro().take(2).array().retro();
	}
	static assert(right("Hellow", "o").equal("ow"));
	
	// aの中からbを見つけてその箇所に", "を挿入
	string test(R)(char[] a, R b)
	{
		a.insertInPlace(a.countUntil(b)+1, ", ");
		return a.idup;
	}
	static assert(test(left("Hellow", "o"), right("Hellow", "o")) == "Hello, w");
}
import std.string, std.range, std.algorithm, std.conv, std.array;
unittest
{
	struct D
	{
		string msg;
		// まとめると
		D opDispatch(string s)() @property
		{
			return typeof(return)(
			    ((a, b)=>a.equal(b))(
			        msg.retro().cycle().take(2),
			        msg.chain(s).retro().take(2).array().retro())
			        ? ((a, b)=>(
			            a.insertInPlace(msg.countUntil(b)+1, ", "), a.idup)
			          )(msg.dup, msg.retro().take(2).array().retro())~s
			        : text(msg,s));
		}
	}
	struct H
	{
		static D opDispatch(string s)() @property { return D(typeof(this).stringof~s); }
	}
	
	static assert(H.e.l.l.o. w.o.r.l.d == D("Hello, world"));
}
import std.string, std.range, std.algorithm, std.conv, std.array;
unittest
{
	struct D
	{
		string msg;
		// 最後のdだけ関数を別途用意して "d! D" を連結させる
		string d(T)() @property
		{
			return text(msg, T.stringof.toLower(), "! ", T.stringof);
		}
	}
	
	static assert(D("Hello, worl").d!D == "Hello, world! D");
}

まとめ

組み合わせると

import std.string, std.range, std.algorithm, std.conv, std.array;

struct D
{
    string msg;
    D opDispatch(string s)() @property
    {
        return typeof(return)(
            ((a, b)=>a.equal(b))(
                msg.retro().cycle().take(2),
                msg.chain(s).retro().take(2).array().retro())
                ? ((a, b)=>(
                    a.insertInPlace(msg.countUntil(b)+1, ", "), a.idup)
                  )(msg.dup, msg.retro().take(2).array().retro())~s
                : text(msg,s));
    }
    string d(T)() @property
    {
        return text(msg, T.stringof.toLower(), "! ", T.stringof);
    }
}
struct H
{
    static D opDispatch(string s)() @property { return D(typeof(this).stringof~s); }
}

pragma(msg, H.e.l.l.o. w.o.r.l.d! D);

void main() {}

つまり

ここまで書いた処理

_人人人人人人人人人人人人人人人人人人人_
> 全部コンパイル時に評価可能!!!! <
 ̄^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^ ̄

お後がよろしいようで

お次は4日目 @__DaLong です。

15
15
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?