Language detail: D
|
number of '+' ratings |
contribution for coverage |
Unsolved challenges
- タブ区切りデータの処理 (Nested Flatten)
- LL Golf Hole 9 - トラックバックを打つ (Nested Flatten)
- 起動オプションの解析 (Nested Flatten)
- echoクライアント (Nested Flatten)
- tailの実装 (Nested Flatten)
codes
テンプレート引数の推論を使って型無しラムダっぽく。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | import std.stdio;
void main() {
auto Y = new class {
auto opCall(_)(_ f) {
return (new class {
auto opCall(_)(_ g) {
return new class {
auto opCall(_)(_ x) {
return f(g(g))(x);
}
};
}
})(new class {
auto opCall(_)(_ g) {
return new class {
auto opCall(_)(_ x) {
return f(g(g))(x);
}
};
}
});
};
};
auto F = new class {
auto opCall(_)(_ f) {
return new class {
auto opCall(_)(_ x) {
if (x == 0) {
return cast(_)1;
} else {
return x * f(x - 1);
}
}
};
}
};
auto factorial = Y(F);
writeln("fact(5) = ", factorial(10));
writeln("fact(5) = ", factorial(20L));
}
|
C++のを真似ようと思ったのですが、なんだか普通になってしまいました。 入力はリテラル、出力はコンパイラメッセージで。
出力:
123 234.5k 345.6M 456.7G 567.8T d202.d(39): static assert "done!"
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | static import std.metastrings;
struct None { enum Symbol = "", Base = 1; }
struct Kilo { enum Symbol = "k", Base = 1e+3; }
struct Mega { enum Symbol = "M", Base = 1e+6; }
struct Giga { enum Symbol = "G", Base = 1e+9; }
struct Tera { enum Symbol = "T", Base = 1e12; }
template SIPrefix(long n) {
static if(n < Kilo.Base)
alias None SIPrefix;
else static if(n < Mega.Base)
alias Kilo SIPrefix;
else static if(n < Giga.Base)
alias Mega SIPrefix;
else static if(n < Tera.Base)
alias Giga SIPrefix;
else
alias Tera SIPrefix;
}
template SIFormat(long n) {
enum SIFormat = ToString!(n / SIPrefix!(n).Base) ~ SIPrefix!(n).Symbol;
}
private template ToString(real x) {
enum ToString = ToString!(cast(long)x) ~ "." ~ ToString!(cast(long)(x * 10))[$ - 1];
}
private template ToString(long x) {
enum ToString = std.metastrings.ToString!(x);
}
pragma(msg, SIFormat!(123));
pragma(msg, SIFormat!(234567));
pragma(msg, SIFormat!(345678901));
pragma(msg, SIFormat!(456789012345));
pragma(msg, SIFormat!(567890123456789));
static assert(false, "done!"); // コンパイル終了
|
使用例も書かないとダメですね。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | import std.conv;
import std.date;
import std.stdio;
string DateEx(string datetime, int tdelta_in_secs)
{
d_time t = std.date.parse(datetime);
d_time new_datetime = t + tdelta_in_secs * std.date.TicksPerSecond;
return std.date.toString(new_datetime);
}
unittest {
assert(DateEx("Mon Sep 01 13:00:00 GMT+0900 2008", -3600) ==
"Mon Sep 01 12:00:00 GMT+0900 2008");
assert(DateEx("Mon Sep 01 13:00:00 GMT+0900 2008", 3600) ==
"Mon Sep 01 14:00:00 GMT+0900 2008");
}
void main(string[] args)
{
string datetime;
int tdelta_in_secs;
if (args.length == 3) {
datetime = args[1];
tdelta_in_secs = toInt(args[2]);
}
else {
d_time now = std.date.getUTCtime;
datetime = std.date.toString(now);
tdelta_in_secs = toInt(args[1]);
}
writefln("%s", DateEx(datetime, tdelta_in_secs));
}
// eof
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | import std.conv;
import std.date;
import std.stdio;
string DateEx(string datetime, int tdelta_in_secs)
{
d_time t = std.date.parse(datetime);
d_time new_datetime = t + tdelta_in_secs * std.date.TicksPerSecond;
return std.date.toString(new_datetime);
}
void main(string[] args)
{
string datetime;
int tdelta_in_secs;
if (args.length == 3) {
datetime = args[1];
tdelta_in_secs = toInt(args[2]);
}
else {
d_time now = std.date.getUTCtime;
datetime = std.date.toString(now);
tdelta_in_secs = toInt(args[1]);
}
writefln("%s", DateEx(datetime, tdelta_in_secs));
}
// eof
|
標準入力から。
1 2 3 4 5 6 7 | import std.stdio, std.conv, std.string;
void main() {
int n = to!(uint)(chomp(readln));
foreach(i; 1..n*2)
writeln("*".repeat(i<n?i:2*n-i));
}
|
標準入力から。
この手の文字列操作はガーベジコレクタのおかげでたやすくできます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | import std.stdio, std.string;
void main() {
auto t = chomp(readln), s = "0".dup;
while(s.length < t.length || s <= t) {
writeln(s);
if(s[0] < '9') {
s[0]++;
} else {
s = "10" ~ s[1 .. $];
}
}
}
|
標準入力から一行読み込んで変換。
1 2 3 4 5 | import std.stdio, std.conv, std.string;
void main() {
writefln("%b",to!(int)(strip(readln)));
}
|
文章はコンパイル時に文字列リテラルとして取り込むので、dmdの-Jオプションでgpl.txtのあるディレクトリを指定してください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | private import std.stdio, std.string, std.regexp;
auto text = import("gpl.txt");
void main() {
int[][string] dict;
auto re = RegExp(r"[\w-]+");
foreach(i, line; text.splitlines()) {
foreach(m; re.search(line)) {
dict[m[0].tolower()] ~= i + 1;
}
}
writeln(dict);
}
|
see: std.date - D Programming Language - Digital Mars
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | private import std.stdio, std.date;
enum Friday = 5;
void main(){
auto count = 0;
foreach(day; Day(getUTCtime) .. MakeDay(2014, 1, 1)) {
auto date = MakeDate(day, 0);
if(WeekDay(date) == Friday && DateFromTime(date) == 13) {
writefln("%04d-%02d-%02d", YearFromTime(date), MonthFromTime(date) + 1, DateFromTime(date));
++count;
}
}
writeln(count);
}
|
1 2 3 4 5 6 7 8 9 10 | private import std.string, std.regexp;
string totitle(in string str) {
return str.sub(r"\b[a-z]", (RegExp m){return m[0].toupper();}, "g");
}
unittest {
assert("LL future".totitle() == "LL Future");
assert("LL day and night".totitle() == "LL Day And Night");
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 | int modular(int n, int low, int high) {
return low + (n + high - low + 1) % (high - low + 1);
}
unittest {
assert(modular(0,100,200) == 100);
assert(modular(50,100,200) == 150);
assert(modular(100,100,200) == 200);
assert(modular(101,100,200) == 100);
assert(modular(-1,100,200) == 200);
assert(modular(1,-5,200) == -4);
assert(modular(-500,-5,-1) == -5);
}
|
出力はSVGにしてみました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | private import std.stdio, std.math, std.random;
void main() {
write(`<?xml version="1.0"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="600" height="600">
<title>ランダムウォーク</title>
<g transform="translate(300,300)">
<circle style="fill:blue" cx="0" cy="0" r="5"/>
<path style="fill:none; stroke:black; stroke-width:1" d="M 0 0`);
auto rgen = Random(unpredictableSeed);
auto uniform = UniformDistribution!(real)(0, PI * 2);
foreach(_; 0 .. 10000) {
auto angle = uniform.next(rgen);
auto move = expi(angle) * 10;
writef(` l %.2f %.2f`, move.re, move.im);
}
write(`"/>
</g>
</svg>`);
}
|
1 2 3 4 5 6 7 8 9 | private import std.stdio, std.string, std.socket, std.socketstream;
void main() {
auto s = new SocketStream(new TcpSocket(new InternetAddress("tinyurl.com", 80)));
scope(exit) s.close;
s.writeString("GET /api-create.php?url=http://ll.jus.or.jp/2008/info/xgihyo HTTP/1.1\r\nHost: tinyurl.com\r\n\r\n");
foreach(char[] line; s) if(line.startsWith("http://")) writeln(line);
}
|
変数名から値を得るだけなら、getenv 関数があります。
see: std.process - D Programming Language - Digital Mars
1 2 3 4 5 | private import std.stdio, std.process;
void main() {
writeln(getenv("PATH"));
}
|
D 2.0 + 標準ライブラリ (Phobos)、Linuxで動作確認。連想配列を作ってしまう方針で。 Phobosには環境変数APIが無いので、Cの environ(7) を直接呼び出します。 C文字列をDのstringに変換する処理が面倒ですね。もっとうまいやり方があるような気がする...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | import std.stdio;
import std.string;
import std.c.linux.linux: environ;
import std.c.string: strlen;
void main()
{
char** p;
string[string] envAA;
for (p = environ; *p != null; p++) {
char[] key_and_value = (*p)[0 .. strlen(*p)]; // "FOO=BAR"
int iEqual = key_and_value.find('='); // index to '='
string key = cast(string)(key_and_value[0 .. iEqual]);
string value = cast(string)(key_and_value[iEqual + 1 .. $]);
envAA[key] = value;
}
envAA.rehash;
foreach(key, value; envAA) {
writefln("%s: %s", key, value);
}
writefln("PATH = %s", envAA["PATH"]);
}
|
生憎、今のところそのような便利ライブラリはなさそうなので生のWin32APIを使わざるを得ません。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | module win32.clipboard;
private import std.c.windows.windows;
private import std.contracts, std.conv;
export extern(Windows) {
HGLOBAL GlobalAlloc(UINT uFlags, DWORD dwBytes);
HGLOBAL GlobalFree(HGLOBAL hMem);
LPVOID GlobalLock(HGLOBAL hMem);
BOOL GlobalUnlock(HGLOBAL hMem);
enum UINT GMEM_MOVEABLE = 2;
BOOL CloseClipboard();
BOOL EmptyClipboard();
UINT EnumClipboardFormats(UINT format);
HANDLE GetClipboardData(UINT uFormat);
BOOL OpenClipboard(HWND hWndNewOwner);
HANDLE SetClipboardData(UINT uFormat, HANDLE hMem);
enum UINT CF_UNICODETEXT = 13;
}
public static class Clipboard {
static void setText(string text) {
enforce(OpenClipboard(null));
scope(exit) CloseClipboard();
auto wtext = to!(wstring)(text);
auto data = enforce(GlobalAlloc(GMEM_MOVEABLE, wchar.sizeof * (wtext.length + 1)));
scope(failure) GlobalFree(data);
{
auto pdata = cast(wchar*)GlobalLock(data);
scope(exit) GlobalUnlock(data);
pdata[0..wtext.length] = wtext;
pdata[wtext.length] = '\0';
}
enforce(EmptyClipboard());
enforce(SetClipboardData(CF_UNICODETEXT, data));
}
static string getText() {
enforce(OpenClipboard(null));
scope(exit) CloseClipboard();
auto data = GetClipboardData(CF_UNICODETEXT);
if(!data) return null;
auto pdata = cast(const(wchar)*)GlobalLock(data);
auto wtext = pdata[0..strlen(pdata)];
GlobalUnlock(data);
return to!(string)(wtext);
}
}
private uint strlen(const(wchar)* s) {
uint len;
while(*s++) len++;
return len;
}
debug(Clipboard) {
import std.stdio;
void main() {
Clipboard.setText("test テスト");
writeln(Clipboard.getText);
}
}
|
ああ、そうか
そもそもコンパイル系言語では変数が宣言されてないとコンパイル時エラーになるので「未定義の変数を操作」なんて状況自体が有り得ないわけですが、 必ず実行できるスクリプト系の言語では有り得るんですね。 それがどんな問題を引き起こすのかまでは分かりませんが、defined-or演算子が必要なのであろうことは分かります。 となるとD言語では「コンパイラが検出してくれるので必要ない」が正解かな。
ちなみにD言語では基本的に宣言した変数は全て初期化されますが、実行速度を重視する場合は初期化しないこともできます。 また、typedefで新しく型を定義するときにデフォルトの初期値を指定できます(変な言い方ですが)。 問題と似たようなケースで使えそうです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | import std.stdio;
//デフォルトの初期値
typedef int myint = 100;
void main()
{
int a;
myint b;
//未初期化の変数を宣言
myint c = void;
//"a=0 b=100 c=(不定)"
writefln("a=%d b=%d c=%d",a,b,c);
}
|
Radix sort (内部アルゴリズムはBucket sort)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | private import std.stdio, std.stdint;
void main() {
int64_t[] a = [int64_t.max, 0, -1, 3, 1 << 17, -1 << 30, int64_t.min];
writeln(a); // [9223372036854775807 0 -1 3 131072 -1073741824 -9223372036854775808]
a.radixSort();
writeln(a); // [-9223372036854775808 -1073741824 -1 0 3 131072 9223372036854775807]
}
private import std.traits : unsigned;
void radixSort(T)(T[] array) if(is(unsigned!(T))) {
alias unsigned!(T) U;
auto uarray = new U[array.length];
foreach(i, ref n; uarray) {
n = array[i] - T.min;
}
foreach(i; 0 .. T.sizeof * 8 / 4) {
auto buckets = new U[][1 << 4];
foreach(n; uarray) {
buckets[n >> i * 4 & 0b1111] ~= n;
}
auto p = uarray.ptr;
foreach(bucket; buckets) {
p[0 .. bucket.length] = bucket;
p += bucket.length;
}
}
foreach(i, ref n; array) {
n = uarray[i] + T.min;
}
}
|
Counting sort
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | private import std.stdio;
void main() {
int[] a = [1, 9, 4, 8, 9, 6, 3, 9, 5, 2];
a.countingSort(1, 10);
writeln(a);
}
void countingSort(int[] array, int min, int max) {
auto counts = new uint[max - min + 1];
foreach(n; array) {
counts[n - min]++;
}
auto p = array.ptr;
foreach(i, c; counts) {
p[0..c] = i + min;
p += c;
}
}
|






ika
#7700()
[
D
]
Rating0/0=0.00
因数分解する方針で。
Rating0/0=0.00-0+
[ reply ]