More Related Content Similar to C++コミュニティーの中心でC++をDISる (20) More from Hideyuki Tanaka (7) C++コミュニティーの中心でC++をDISる2. 自己紹介
• 田中 英行 (@tanakh, id:tanakh)
• (株)Preferred Infrastructure 勤務
• Haskell好き/C++嫌い
• C++歴13年
– 主にWindowsでゲームを作ったりしていました
– 最近は仕事でコンソールアプリ書いてます
5. ご存知でしたか?
C++が今年の
“Discriminating Hackersが選ぶ言語”
に選ばれていたという事実を・・・
6. Discriminating Hackersの選ぶ言語
とは?
• ICFP という関数プログラミングの学会が
• 毎年プログラミングコンテストを開催しています
• 優勝チームの使っていた言語が、
“Discriminating Hackersの選ぶ言語”
として讃えられ、無制限に自慢できる権利を与
えられます
8. よりにもよって、
手続き型の、
それもC++が、
関数プログラミングの学会主催の
コンテストで、
Discriminating 言語だなんて!
11. やりました!
• 優勝者になって、好きな言語を選べる!
– しかし、ものすごくモメる
• とりあえず使った言語列挙する
– C++、Haskell、Python
– すごくオーソドックスな組み合わせですね!
• ということで、今年(9月頃まで?)はくれぐれ
もこれらの言語の悪口は謹んで頂くように!
12. しかし。
• 私はC++が好きではない
– (C++を使ったのは主に私なんですが…)
• 私が選んだのだから(Discriminating Hackerな
のだから)その効力は私には及ぶまい(と勝
手にルールを解釈)
• そこで・・・
18. 同じ型を何度も書かされる
• (int, int) -> int なる map を扱うとき
map<int, map<int, int> > mm;
for (map<int, map<int, int> >::iterator p = mm.begin();
p != mm.end(); p++){
map<int, int> &r = p->second;
for (map<int, int>::iterator q = r.begin();
q != r.end(); q++){
....
}
}
20. 例
• int -> double に変更
map<int, map<int, double> > mm;
for (map<int, map<int, double> >::iterator p = mm.begin();
p != mm.end(); p++){
map<int, double> &r = p->second;
for (map<int, double>::iterator q = r.begin();
q != r.end(); q++){
....
}
}
21. typedef 使え
typedef map<int, double> ogram;
typedef map<int, ogram> tgram;
tgram mm;
for (tgram::iterator p = mm.begin();
p != mm.end(); p++){
ogram &r = p->second;
for (ogram::iterator q = r.begin();
q != r.end(); q++){
....
}
}
23. 0x使え
map<int, map<int, double> > mm;
for (auto p = mm.begin();p != mm.end(); p++){
auto r = p->second;
for (auto q = r.begin();q != r.end(); q++){
....
}
}
26. 型推論が非力
• そもそも型推論とは何ぞや?
– 型なしプログラムから型ありプログラムの再構築
(Type Reconstruction)
• C++0xでは、すべての型を推論できるわけではな
い
– ○ローカル変数(auto)
– ○ラムダ式の返り値
– ×関数の引数
– ×クラスメンバ
• Hindly-Milner型の型推論ができないものか
28. テンプレート
• みんな大好きテンプレート
• だがしかし!
• テンプレートおかしいよテンプレート
• C++のストレスの約8割はこいつの所為
32. その代償
• C++では、テンプレート関数を宣言時ではなく、
使用時にインスタンス化し、それに対して型
付けを行う
• これはどういう事を招くか?
– テンプレート関数(クラス)を分割コンパイルでき
ない
– テンプレート関数自体に対しては型が付かない
– (得られるコンパイルエラーが往々にして不可解)
36. ヘッダに書くことによる問題
• namespace地獄
std::map<int, std::map<int, int> > mm;
for (std::map<int,std::map<int, int> >::iterator
p = mm.begin();
p != mm.end(); p++){
std::map<int, int> &r = p->second;
for (std::map<int, int>::iterator q = r.begin();
q != r.end(); q++){
....
}
}
– using namespace させて…
39. 例(2)
• もちろん、人がある程度注釈することはできる
template <class InputIterator,
class OutputIterator,
class UnaryOperator>
OutputIterator transform(InputIterator first1,
InputIterator last1,
OutputIterator result,
UnaryOperator op);
• しかし、これでは不十分
– Input/OutputIteratorが満たす要件は?
– UnaryOperatorとはなんなのか?
– これらはドキュメントに書くしかない
• それは何の保証もない
41. 今は亡きコンセプトさん
/二二ヽ
| 今 |
| 瀬 |
| 腑 |
| 戸 |
| 之 |
__| 墓 |__
/ └──┘ \
|´ ̄ ̄ ̄ ̄ ̄ ̄| ソ
ソ::::::::::::::::::::::::::::::::ソソ
/ ソ ̄|;;;;;;;lll;;;;;;;| ̄ソ \
|´ ̄ ̄ |. [廿] .|´ ̄ ̄.|
|:::::::::::::::| |::::::::::::::|
|:::::::::::::::| ̄ ̄ ̄|::::::::::::::|
. ̄ ̄ ̄|_______|´ ̄ ̄゛
46. ラムダ式
• Haskell
– ¥x -> x+1
• OCaml
– fun x -> x
• Scheme
– (lambda (x) x)
• C++
– [](int x){ return x+1; }
48. ラムダ式
• とにかくキモすぎる。
int main()
{
[](){[](){[](){[](){[](){[](){}();[](){}();}();
[](){[](){}();[](){}();}();}();}();[](){[](){[]()
{[](){}();[](){}();}();[](){[](){}();[](){[](){[]
(){[](){}();[](){}();}();[](){[](){}();[](){}();}
();}();}();}();}();}();}();[](){[](){[](){[](){[]
(){}();[](){[](){[](){[](){[](){[](){[](){}();[](
){}();}();[](){[](){cout<<"やぁ(´・ω・`)"<<endl;}();
[](){}();}();}();}();[](){}();}();[](){[](){}();[
](){}();}();}();}();}();[](){[](){}();[](){}();}(
);}();}();[](){[](){[](){[](){}();[](){}();}();[]
(){[](){}();[](){}();}();}();}();}();}();
}
52. 関数の型
• 関数の型を扱いたい時、functionクラスを用
いると簡単
– しかし、パフォーマンスの低下
• インライン展開されないなど
– 単なるテンプレートパラメータが好まれる
• 結局ドキュメントとしての型が得られない
template <class A> template <class F, class A>
A twice(function<A(A)> f, A v) A twice(F f, A v)
{ {
return f(f(v)); return f(f(v));
} }
53. 多相関数
• C++0xのラムダ式は多相にならない
– 例えば id x = x, id :: forall a . a -> a
– のようなものが書けない
– template <class A>[](A x){ return x; }
– ↑ こういうモノが書けない
54. テンプレート関数の値
• C++ではテンプレート関数、それ自体は値とし
て扱えない
– 具体的な型でインスタンス化しないと値にならない
– つまり、そのような式に付く型がない
template <class T>
T id(T x){ return x; }
int main()
{
// auto f = id; // <- これにつく型は?
auto g = id<int>; // <- これは int->int
}
55. 総称型がない
• C++の型には総称型がない
– すべての型は具体的な型の組み合わせ
– つまり型パラメータがない
– 多相関数に付けられる型がないのもまあ頷ける
• ところが、Boost.Lambdaでは多相関数が扱え
るらしい?
– 一体どういう事なのか?
56. Boost.Lambdaでのラムダ式
• 何故かできてしまう
int main()
{
using namespace boost::lambda;
auto f = _1; // ¥x -> x
cout<<f(1)<<endl; // -> 1
cout<<f(3.14)<<endl; // -> 3.14
}
• fの型は何なのか?
– forall a . a -> a をどうやって表現している?
57. Boost.Lambdaの型
• 出力してみる
cout<<demangle(typeid(f).name())<<endl;
boost::lambda::lambda_functor<boost::la
mbda::placeholder<1> >
• ??
58. Boost.Lambdaの型(2)
• もう少し複雑な例
int main()
{
using namespace boost::lambda;
auto f = cout << _1 << '¥n';
cout<<demangle(typeid(f).name())<<endl;
}
boost::lambda::lambda_functor<boost::lambda::lambda_functor_base<boost::lambda::bitwise_action<boost::
lambda::leftshift_action>,
boost::tuples::tuple<boost::lambda::lambda_functor<boost::lambda::lambda_functor_base<boost::lambda::b
itwise_action<boost::lambda::leftshift_action>, boost::tuples::tuple<std::ostream&,
boost::lambda::lambda_functor<boost::lambda::placeholder<1> >, boost::tuples::null_type,
boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type,
boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type> > >, char const,
boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type,
boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type,
boost::tuples::null_type> > >
61. パターンマッチのような物…?
• なんか提案されているらしい
– さすがにこれは…
variant<
int
, pair<int,double>
, pair<int,int>
, pair<double,int>
> var;
switch_(var)
|= case_< pair<_1,_1> >(...) // matches pair<int,int>
|= case_< pair<int,_> >(...) // matches pair<int,*>
|= case_< pair<_,_> >(...) // matches pair<*,*>
|= case_< int >(...)
;
63. カリー化の旨み
• 純粋関数的に状態を持ちまわるというのが
とてもやりやすくなる
cnt acc i = (acc, cnt (acc+i))
let a = cnt 0 in
let (v, b) = a 1 in –- v = 0
let (w, c) = b 2 in –- w = 1
let (x, d) = c 3 in –- x = 3
...
• オブジェクト vs 関数
• 関数プログラミングでは、次の状態として
関数を返すことがよくある(e.g. Iteratee)
65. まとめ
• まだまだ言いたいことはありますが…
– iteratorはクソ
– 例外周りがいろいろクソ
– ADLはクソ
– moveはクソ
– 右辺値参照はクソ
– GCないとかクソ
– スマポはクソ
– …
• C++もいいところはあると思います
– 適当に書いてもそこそこ速いコードが書ける
– 0xでそれなりに改善されてる