From POE to Erlang
A Perl programmer's journey into concurrency-oriented programming
(Perlプログラマによる並行指向プログラミング)
Ever needed to write a concurrent program in Perl?
(Perlで並行プログラムを書かなきゃいけなくなったことはありますか?)
As usual, you have lots and lots of options...
(例によって選択肢はたくさんあります)
Usually something else (the OS) helps out
(ふつうはほかのものが助けてくれます)
Best example is Apache: multiple Perl processes
(Apacheがなによりの例でしょう)
Perl is a GLUE language: We leave the messy bits
to others, and glue the finished parts
(Perlはのり付けをするだけ。面倒くさい部分はほかの人にまかせておけばいい)
Concurrency and Perl
並行処理とPerl
- While Perl5 today has threads, most of us basically write
single-threaded Perl code
(Perl5にはスレッドがありますが、たいていの人は基本的にシングルスレッドなコードを書きます)
- Threads in Perl5, (known as Interpreter Threads or ithreads)
are nice, but having been introduced relatively recently, they still are
not in widespread use
(Perl5のithreadも悪くはないですが導入されたのは比較的最近なのであまり使われていません)
- In Perl6, however, support for concurrency (threads, STM)
is not just an afterthought, so things will be different
(Perl6は並行処理をサポートするので話は変わります)
- But that's Perl6: We use Perl5 in our day job
(でも、それはPerl6の話ですし、ふだんの仕事で使うのはPerl5です)
- In other words, the average day in the Perl5 programming life
has very few occasions where one needs to mess with concurrency
(つまりふつうのPerl5プログラマが並行処理をすることはきわめてまれなのですね)
The Perl5 life: Thread worry-free
Perl5ライフ: スレッドなんて気にしない
- Not developing in a threaded environment has afforded us
(at least, those who've never used ithreads much) a degree
of unworried complacency
(スレッド環境で開発しなければ心配する必要もない)
- Deadlocks and race-conditions to us, were things that
only hapless Java and C++ programmers had to mess with.
(デッドロックとかレースコンディションなんてJavaとかC++のプログラマにまかせておけばいい)
- The hapless Java programmers themselves, mostly
gave up building GUI applications and hid behind the
safety of web application frameworks.
もっとも、JavaプログラマはGUIアプリの構築なんてあきらめてWebアプリケーションフレームワークの殻の中に逃げ込んじゃったけどね
- One click at a time, one HTTP request at a time,
one Java Servlet thread, and a request life-cycle in
which to do all the work in a linear, sequential
manner
(クリックも、リクエストも、Servletのスレッドもひとつ。ライフサイクルも線形でシーケンシャル)
The Perl5 life: Thread worry-free
Perl5ライフ: スレッドなんて気にしない
- How often does an average web-developer have to worry
about concurrency? At least as far as their language or
runtime is considered? Databases have transactions,
and are complex entities that provide concurrent
access to shared 'state'
(ふつうのWebプログラマが並行処理を気にしないといけない場合? しかも言語やランタイムが考慮できる範囲で? データベースのトランザクション処理とか、複雑なエンティティなら共有されている「ステート」に並行アクセスするかも、という程度)
- Because threads are so hard to get right, application
developers leave the concurrency to the lower levels -
the server or the framework developers
(スレッドを正しく扱うのはとても難しいので、アプリケーションを開発する人たちは並行処理をサーバとかフレームワークの開発者にまかせてしまう)
For example...
(たとえば)
- UNIX and
fork()
- CGI programs (fork for each request)
(CGIプログラムはリクエストごとにfork)
- mod_perl programs (Concurrency via a preforked Perl pool)
(mod_perlプログラムはpreforkしたPerlプールを利用して並行処理)
- FastCGI (preforked long-running Perl procs)
(FastCGIはpreforkしてPerlのプロセスを走らせっぱなしにする)
- Anybody know an application in Perl that uses
ithreads?
(Perlでithreadsを使っているアプリって知っていますか)
- Event loops: Perl/Tk, Perl/GTK+ (イベントループ)
- Cooperative Multitasking - POE (協同マルチタスキング)
- POE-like frameworks: Perlbal (POE風のフレームワーク)
in other words...
(いいかえると)
- perl is at home in unix (perlのホームグラウンドはunix)
- and there are multitasking options... (マルチタスクのオプションもそろっている)
fork()
select loops
- posix threads (not really an option for perl) (perlではあまり使われない)
- perl interpreter threads (perlのithreads)
Hmm...
fork(): slow, overhead (遅い、オーバーヘッドがある)
- Threads are scary (スレッドはこわい)
select loops are hard to understand (selectループは理解しづらい)
- Concurrency in any other good way? Hmmm (ほかにいい方法ある?)
Select Loops are difficult, but there are frameworks
(selectループはむずかしいけど、フレームワークはある)
POE is...
From http://poe.perl.org
POEtry ... Panel Of Experts ... Parallel Object Executor ... Parcel Out
Execution ... Parenthetically Over-Engineered ... Parity Of Evil ... Part Of
Elephant ... Particles Of Eternity ... Party On, Ebenezer ... Passed Out from
Excitement ... Pathetically Over-Engineered ... Peace On Earth ... Penes
Over-Emphasized ... Perfect Orange Eater ... Perfectly Oblique Egg-plant ...
Periodically Orbits Earth ... Perl Obfuscation Engine ... Perl Object
Environment ... Perl: Objectively Excellent ... Perl Objects for Enterprises
... Perl Objects for Events ... Perl On Extasy ... Perl Operating Environment
... Perl Operator Extravaganza ... Perl Over Easy ... Perl Over Ethernet ...
Perl Overdrive Engine ... Perlmud Offers Expansions ... Perpetual Orgone Energy
... Persistent Object Environment ... Persnickity Oblong Erudition ... Phallic
Overture Ejaculate ... Philanthropic Organization Enterprises ... Physician
Order Entry ... Piece Of Eight ... Pigs, Owls, and Elephants ... Piles Of Eugh
... Pious Object Excelsior ... Plain Old English ...
POE Comes with:
(POEについてくるもの)
- It's own Kernel! (自前のカーネル)
- Processes (NOT UNIX Process: POE processes) (プロセス、といってもUNIXのではなくPOEのプロセスですが)
- Also called Sessions: They are the unit of
multitasking in POE (セッション。POEのマルチタスクの単位)
- A POE program consists of many Sessions (POEプログラムは多くのセッションからなります)
- Sessions consist of Events (セッションはイベントからなります)
- Events
yield to one another (イベントはお互いに譲り合います)
- POE parcels out execution: One event after another (POEは処理を分配します)
- Abstraction: Sessions seem simultaneous (抽象化: セッションは同時に起こっているように見えます)
Silly Example
(くだらない例)
We have a good friend who makes us sandwiches
(私たちにはサンドイッチをつくってくれる友人がいます)
We can eat as we ask her to keep making sandwiches for us
(サンドイッチをつくってほしいとお願いすれば食べさせてくれますが)
... till she gets bugged with us..
(度が過ぎると怒り出します)
Silly Sandwiches
(くだらないサンドイッチ)
A recursive loop, POE-ish
(POE風の再帰ループ)
sub tick_tock {
my ($me) = $_[KERNEL]->alias_list();
my $now = time();
print "$me : $now\n";
$_[KERNEL]->delay('tick_tock', 1);
}
my @types = qw(
cheese
egg
BLT
chicken
chicken_and_cheese
tomato_and_cucumber
jelly
chocolate_cream
);
Silly Sandwiches
(くだらないサンドイッチ)
POE::Session->create(
inline_states => {
_start => sub {
my ($heap, $kernel) = @_[HEAP, KERNEL];
$kernel->alias_set('friend_in_need');
$heap->{i} = 0;
print "*** I can make you a sandwich!\n";
$kernel->yield('tick_tock');
},
make_sandwich=> sub {
my ($kernel, $heap, $type) = @_[KERNEL, HEAP, ARG0];
$heap->{i}++;
my $i = $heap->{i};
if ($i < 4) {
# make a sandwich
print "*** Making a $type sandwich for you.\n";
$kernel->post(faiz => sandwich_ready => $type);
} else {
$kernel->yield('fed_up');
}
if ($i > 4) {
$kernel->post(faiz => 'i_hate_you');
}
},
fed_up => sub {
print "*** go make your own sandwiches.\n";
},
tick_tock => \&tick_tock,
},
);
Silly Sandwiches
(くだらないサンドイッチ)
POE::Session->create(
inline_states => {
_start => sub {
my $kernel = $_[KERNEL];
$kernel->alias_set('faiz');
$kernel->yield('tick_tock');
$kernel->yield('beg');
},
beg => sub {
my $i_want_to_eat = shift @types;
unless ($i_want_to_eat) {
$_[KERNEL]->yield('time_for_a_drink');
return;
}
print "--> I feel like a $i_want_to_eat sandwich.\n";
$_[KERNEL]->post(
friend_in_need => make_sandwich =>
$i_want_to_eat
);
$_[KERNEL]->delay('beg', 0.5);
},
sandwich_ready => sub {
my ($sandwich) = $_[ARG0];
print "--> yummy $sandwich sandwich (burp)\n";
},
time_for_a_drink => sub {
print "--> Faiz: thirsty now.\n";
},
tick_tock => \&tick_tock,
}
);
$poe_kernel->run();
GUI Programming
(GUIプログラミング)
Can be yucky.
(ひどい目にあうこともある)
- Perl/Tk. Or even GTK+
- We want to do something that may block.
(しようとしていることがブロックされるかもしれない)
- **Great**, because it end up blocking the whole UI! :-(
(すごいな。最後にはUI全体がブロックされてしまう)
- What if we use threads?
(どうしてスレッドを使うのか)
Examples...
(たとえば)
# We want to do this
while (sleep(100)) {
my $response = $ua->request($request);
# waiting....
my $data_to_display = $self->parse($response);
}
# WHILE we also do this....
Gtk2->main;
# Or While we do this:
MainLoop();
Perl/GTK+ and POE
use Gtk2 -init;
use POE::Kernel { loop => "Glib" };
use POE::Session;
POE::Session->create(
inline_states => {
_start => sub {
$_[KERNEL]->post('fetch');
},
fetch => sub {
my $request = ...; # Create a HTTP::Request
$_[KERNEL]->post(ua => request => response => $request);
},
response => sub {
my ($req_packet, $resp_packet) = @_[ARG0, ARG1];
my $response = $resp_packet->[0];
my $data_to_display = parse($response);
$_[HEAP]->{widget}->setText($data_to_display);
$_[KERNEL]->delay(fetch => 100);
}
}
);
$poe_kernel->run();
What do the Gtk-Perl guys say about threads?
(Gtk-Perlの人たちはスレッドのことをどう思っているんだろう)
Can I use threads with Gtk2-Perl?
(Gtk2-Perlでスレッドって使えるの?)
Yes, if you are very careful. (気をつければ使える)
In general, you want to mess with the gui from only one thread, and then
you're safe. An extra wrinkle for gtk2-perl is that you need to create your
extra threads before you create any gtk2-perl objects or widgets.
(ふつうGUIをいじる場合はひとつのスレッドのみからにするものですし、そうしている分には問題ないですが、gtk2-perlの場合、オブジェクトやウィジェットを作る前にかならず余分のスレッドをつくっておく必要があります)
There are a few threads in the mailing list archives about this topic. This
message, in particular, includes working code:
http://mail.gnome.org/archives/gtk-perl-list/2003-November/msg00028.html
(メーリングリストにもいくつかスレッドがあります。動作するコードも紹介されています)
What do the Gtk-Perl guys say about threads? (continued)
(Gtk-Perlの人たちはスレッドのことをどう思っているんだろう)
Because of this mess, it's usually best to avoid threads if you can. If you
need to monitor a file or socket for input, use Glib::IO->add_watch to wait
for events on that file descriptor. You can also spawn other programs and
communicate via pipes, and even use Gtk2::Plugs and Gtk2::Sockets to put
that child process' widgets into the parent's gui.
(このような問題があるのでふつうはスレッドを避けた方がよいですが、
ファイルやソケットを監視する場合はGlib::IO->add_watchを使ってイベント待ちをしてください。
ほかのプログラムを実行したり、パイプ越しにやりとりすることもできますし、
Gtk2::PlugsやGtk2::Socketsを使えば子プロセスのウィジェットを親のGUIに入れることもできます)
POE is a Framework
(POEはフレームワーク)
- POE:: name-space on CPAN is vast (非常に広い名前空間)
- Highly modular (高度にモジュール化されている)
- Many different types of Servers and Clients (さまざまなタイプのクライアント、サーバ)
- Non-blocking, Event driven POE equivalents
are available for many common tasks (ノンブロッキングなイベント駆動のPOE互換ライブラリが利用できる場面も多い)
- Protocol Stack Abstraction (プロトコルスタックの抽象化)
Data Marshalling
(データマーシャリング)
POE::Component::Server::TCP->new
( Alias => "myserver",
Port => 7777,
ClientInput => sub {
my ( $session, $heap, $input ) = @_[ SESSION, HEAP, ARG0 ];
print "Session ", $session->ID(), " got: $input\n";
$heap->{client}->put( "you say $input." };
},
ClientFilter => "POE::Filter::Line",
);
Protocol Stacks
(プロトコルスタック)
POE::Component::Server::TCP->new
( Alias => "myserver",
Port => 7777,
ClientInput => sub {
my ( $session, $heap, $input ) = @_[ SESSION, HEAP, ARG0 ];
print "Session ", $session->ID(), " got: $input\n";
$heap->{client}->put( "you say $input." };
},
ClientFilter => new POE::Filter::Stackable(
Filters => [
"POE::Filter::Zlib",
"POE::Filter::Line",
]);
);
Concurrency without Locks
ロックのない並行処理
'flavors' and variations of concurrency we hear of
私たちが並行処理といって思い浮かべるのは
- POE (Event-Driven, Cooperative Multitasking)
(イベント駆動、協同マルチタスキング)
- STM (Software Transactional Memory) and Perl6 threads
- Erlang-style actor-model concurrency
(Erlang風のアクターモデル並行処理)
Moore's Law - Remember?
(ムーアの法則 - 覚えていますか)
"The number of transistors on a chip will double every two years."
(チップ上のトランジスタの数は2年ごとに倍になる)
In the 1990's, Moore's Law was interpreted as the doubling of processor power
every one and a half years (18 months).
(1990年代にはプロセッサの能力が1年半で倍になると解釈されていました)
So, has Moore's Law Failed?
(これは間違っていたのでしょうか?)
Is Moore's Law Dead?
(ムーアの法則は死んだのか)
Is the free lunch over?
(フリーランチは終わった?)
- Moore's Law was about transistors on a chip,
and NOT really about megahertz or gigahertz.
(ムーアの法則は「チップ上のトランジスタの数」に関するもの。メガヘルツとかギガヘルツとか、ほんとは関係ない)
- Clock speeds were an outcome of Moore's Law.
(クロック数なんてムーアの法則の「結果」でしかない)
- If clock speeds are not considered true indicators of CPU
performance, then GIGAFLOPS could be, but again,
GIGAFLOP increase was itself also an outcome of
Moore's Law.
(じゃあ、GIGAFLOP? それも結局はムーアの法則の「結果」だよね)
- Chip manufacturers are still able to pack in more and more
transistors per chip (at least more and more transistors per computer); Sure, there
will come a hard limit. But as of today, the transistor
count hasn't plateaued yet.
(チップメーカーはまだまだ搭載するトランジスタの数を増やせる)
(ハード的な限界はあるだろうけど、トランジスタの「数」についてはまだそこまで行ってない)
Never mind Moore's Law
(ムーアの法則はどうでもいいけど)
The point is, that processor speeds
haven't been increasing too much lately.
(最近プロセッサの「速さ」は速くなってない)
- Processors are improving differently than before.
(プロセッサの進化の仕方は変わってきているんですね)
- There have been other big improvements:
(ただ、ほかのところではずいぶん性能がよくなっている)
Better power management (Pentium M), (電源管理)
Better chipsets, IO, bandwidth improvements, (チップセットやIO、帯域の向上)
64-bit computing (AMD64, or Intel EM64T), (64ビットコンピューティング)
Virtualization, (仮想化)
Hypertransport et al, (ハイパートランスポート)
and most significantly - Parallelism
(Everything from Hyperthreading to
Multicore) (そしてなにより並列化)
The multi-core future (present?)
(マルチコアの将来)
- Sun's Niagara - UltraSPARC T1 - 8 cores, 4 threads each -
32 threads of execution (8コアにそれぞれ4スレッドで32スレッド)
- UltraSPARC T2 - 8 cores, 8 threads each... (8コアにそれぞれ8スレッド)
- The SMP-enabled multiprocessor version, the UltraSPARC T2+,
already available this April, can do 128 threads of simultaneous execution (SMP対応マルチプロセッサもこの4月に発売になったので同時に128スレッドの処理も可能)
- Intel's future seems to have a multicore hue as well:
Tera-scale Computing Research Whitepaper:
http://download.intel.com/research/platform/terascale/terascale_overview_paper.pdf
(Intelも将来的にはマルチコアに向かう模様)
- Intel's Quad-core Yorkfield processor is around the corner (IntelのQuad-coreプロセッサも近々登場)
- Even the PS3 has an 8-core Cell processor (PS3は8コアセルプロセッサを搭載)
better, but not faster
(性能はあがったけど、速くはなっていない)
- In 1996, it was easier to get away with writing a slow program
(1996年の方が遅いプログラムを書かないようにするのは簡単だった)
- ...because a year and a half later,
it would probably be fast enough
(of course that didn't mean a happy ending for some of
the slower programs: PC's are fast enough to run Java applets now,
but applets are still quite dead :-))
(なにしろ1年半もすればたぶん十分な速さになってくれたから)
if not faster, then what?
(速さでなければ、どこがよくなったのか)
- We can't count on the same single-processing speed up
anymore. free lunch, in that sense, is over
(ただ、もうそういうシングルプロセスの高速化は望めない。その意味でフリーランチは終わったわけです)
- OS kernels can benefit; more processes/threads can be
scheduled to run simultaneously
(OSのカーネルには恩恵があるかも。同時に実行できるプロセス/スレッドが増えるから)
- Your application might benefit as well; if it
is parallelizable
(アプリケーションも恩恵を受けるかもしれません。並行化されていればの話ですが)
- Ever written a program for a 128-thread processor?
(128スレッドプロセッサ用のプログラムを書いたことなんてありますか)
The Multicore future
(マルチコアの将来)
Unless you're satisfied with nothing more than just the OS
benefiting
(OSが恩恵を受ければ満足という人以外は)
- Programs will need to be re-written if you
want them to run faster on such hardware
(速くしたい、あるいはそういうハードで動かしたい場合は書き直す必要があります)
- Probably redesigned
(というかたぶん設計からやり直した方がいい)
Models for Concurrency
(並行モデル)
Historically, there have been two main theoretical models
for concurrency
(歴史的に大事な理論は2つ)
- Shared State Concurrency (共有ステート並行処理)
- Dijkstra (ダイクストラ)
- The Dining Philosophers (「食事をする哲学者」問題)
- Pessimistic Locking does not scale (悲観ロックはスケールしない)
- Solutions exist, but in real life,
locking requires great care and is error-prone (解決策はあるが、現実問題としてロックには気をつかうしエラーのもとにもなりやすい)
- Message Passing Concurrency (メッセージ渡し並行処理)
- The Actor Model (アクターモデル)
- Share-nothing, just pass messages (共有せずメッセージを渡すのみ)
- Asynchronous (非同期)
- Sometimes models the real world better (モデルの方がよい場合もある)
Erlang: From Telecom-Specific to General Purpose
(Erlang: 通信業界御用達から一般用に)
-
Designed by Ericsson (Named after mathematician Agner Krarup Erlang, but
could also allude to Ericsson Language), since they wanted the following properties:
(設計したのはEricssonという人。こんな特徴がある)
- Rapid Development; Something like Lisp or Prolog,
but something that could be used for concurrent programs
(ラピッド開発: LispとかPrologに似ていながら並行プログラムにも耐えるもの)
- Fault Tolerance: Errors must not bring the system
down or interrupt the service
(耐障害性: エラーが出てもシステムを止めたりサービスを中断させてはならない)
- Concurrency, without the mess of locks
(並行性。ただしごちゃごちゃとロックをしない)
- The ability to spawn thousands of lightweight 'processes'
at will, and at very little cost
(軽量プロセスを数千個、気軽に、またごく小さなコストで立ち上げられる能力)
- Very long uptime, almost perpetual
(アップタイムが非常に長い。ほぼ永久)
- Real-time properties
(リアルタイムプロパティ)
Erlang: From Telecom-Specific to General Purpose
(Erlang: 通信業界御用達から一般用に)
- Many Functional languages are used more in academia/research;
but Erlang has seen massive real-world use in the Telecom industry
(関数型言語の多くは大学や研究機関で使われているけど、Erlangは実際の通信業界で大規模利用されている)
- Ejabberd, Jabber.org's de-facto server, is implemented in Erlang
(Jabber.orgのデファクトサーバEjabberdもErlangで実装されている)
- Apache CouchDB
- Twitter
- Facebook Chat
- Wings3D
The Erlang Programming Language
(Erlangという言語の特徴)
- Functional - no side effects, easier concurrency
(関数型 - 副作用なしに並行処理がしやすくなる)
- Single Assignment - no mutable state, lesser need for locks
(単一割当て - 状態変化をなくしてロックの必要を減らす)
- Dynamically typed - well, this is always subjective, huh.
(動的型付け - まあ、これはいつでも非オブジェクト指向なんだけど)
- Real-time (they call it soft real-time)
(リアルタイム性)
- Strict Evaluation (differs from Haskell)
(正格評価)
- Pattern matching (reminiscent of Prolog)
(パターンマッチング)
- List Comprehensions!
(リスト内包表現)
The Erlang Programming Language
(Erlangという言語の特徴)
- Concurrent (並行処理)
- Pure Asynchronous Message Passing
(純粋な非同期メッセージ渡し)
- Based on the Actor Model
(アクターモデルベース)
- Lock-less, share-nothing policy
(ロックも共有もしないというポリシー)
- The runtime supports spawning thousands,
even millions of 'processes' or lightweight
threads
(ランタイムは数千、数百万の「プロセス」と呼ばれる軽量スレッドを実行可能)
- No objects!
In Python or Java, everything is an object: In Erlang, everything
is a process (オブジェクトはない。PythonやJavaではすべてがオブジェクト。Erlangではすべてがプロセス)
Erlang: Variables, Atoms, Primitive datatypes
(Erlang: 変数、アトム、プリミティブデータ型)
- Atoms: think of these as symbols that never change. (決して変化しないシンボルだと思えばいい)
abcd
my_atom
starts_with_lower_case
'Anything in single quotes'
- Variables - or should we call them 'bindings': (変数 - それとも「束縛」と呼ぶべき?)
Pi
Name
Mood
Values can be assigned to bindings: (束縛に値を割り当てることもできる)
Pi = 3.14 %% Pi is now a float
Mood = happy %% Mood is now the atom 'happy'
Name = "Faiz" %% Name is now a string, "Faiz"
Binding names always start with a capital letter!
(Weird, but this is a Prologism... Prolog was used a lot
during Erlang's early bootstrapping history)
(束縛名はかならず大文字で始めること! これはPrologの名残。Erlangの初期にはよくPrologが使われていた)
Erlang: Data Structures
データ構造
- Tuples: Simple compound data with a fixed number of terms. (タプル: 要素の数が固定のシンプルなデータ構造体)
{name, "Faiz", mood, nervous}
{error, "Bad news!"}
{Student, Grade}
Extracting data from tuples:(タプルからデータを取り出す)
> Point = {x, 100, y, 56}. %% Represent a 2D point as a tuple
> {x, XVal, y, _} = Point. %% Pull out the X-value
> XVal. %% What's the X-value?
100
- Lists (What would a functional language be without them?)
(リスト。これのない関数型言語なんて)
[1, 2, 3]
[{name, "Faiz", mood, happy},
{name, "Robbin Hood", mood, smug},
{name, "Gollum", mood, miffed}]
Erlang: Cons The Magnificent
(Erlang: 偉大なるCons)
List Operations are both Lispy and Prologesque
(リスト操作はLisp風味でありProlog風味)
- The 'pipe' operator denotes a cons cell: (パイプ演算子はconsセルをあらわしています)
> List = [1, 2, 3, 4, 5, 6].
> [First|Rest] = List.
> First.
1
> Rest.
[2,3,4,5,6]
-
Build a list:
> ListWithZero = [0|List].
> ListWithZero.
[0,1,2,3,4,5,6]
Erlang: Pattern Matching
Used with pattern matching to implement a simple
function to double all numbers in a list:
(パターンマッチとともにリスト内のすべての数を2倍する単純な関数を実装)
double([H|T]) -> [2*H|double(T)];
double([]) -> [].
> double(List).
[2,4,6,8,10,12]
Erlang: Variables that don't 'vary'
(Erlang: 変化しない変数)
Single Assignment (as in Haskell)
(単一割り当て)
Erlang: Functional, Dynamic
(Erlang: 関数的、動的)
Lambda is fun!
(ラムダはおもしろい)
| Erlang | fun (X) -> X+1 end. |
| Javascript | function (x) { return x+1 } |
| Perl | sub { my $x = shift; $x+1; } |
| Lisp/Scheme | (lambda (x) (1+ x)) |
| Haskell | \x -> x + 1 |
| Ruby | lambda {|x| x+1 } |
Erlang: Functional Programming Language
(Erlang: 関数型プログラミング言語)
- Supports all the functional programming
techniques: functions are first-class, may
be passed around as return values or arguments.
(関数型プログラミング技術はすべてサポート。関数は最高。返り値や引数にすることもできる)
divisible(By) ->
fun(N) ->
N rem By == 0
end.
At runtime, make a function to test divisibility by 3
(実行時に3で割れるかどうか確認する関数が生成される)
> DivBy3 = divisible(3). %% DivBy3 is a function
> DivBy3(77). %% invoke it.
false
> DivBy3(78).
true
> lists:map(DivBy3, [1,3,6,7,9,5]).
[false,true,true,false,true,false]
> lists:filter(DivBy3, [1,3,6,7,9,5]).
[3,6,9]
Erlang: List Comprehensions
(リスト内包表現)
> [X || X <- [1,a,2,s,3,d,4,f,5,g,6,h], integer(X), X rem 2 == 0].
[2,4,6]
> [{X, X-1} || X <- [1,a,2,s,3,d,4,f,5,g,6,h], integer(X), X rem 2 == 0].
[{2,1},{4,3},{6,5}]
Here's a Quicksort Implementation:
(クイックソートの実装例です)
qsort([]) -> [];
qsort([Pivot|T]) ->
Left = [X || X <- T, X < Pivot],
Right = [Y || Y <- T, Y >= Pivot],
qsort(Left) ++ [Pivot] ++ qsort(Right).
Of course, this code is not the most efficient (the
++
is apparently slow, etc). But it does show list comprehensions in
action.
(もちろんこのコードはもっとも効率のよいものではありませんが、
リスト内包表現の実例にはなるでしょう)
Erlang: Quicksort
qsort([]) -> [];
qsort([Pivot|T]) ->
Left = [X || X <- T, X < Pivot],
Right = [Y || Y <- T, Y >= Pivot],
qsort(Left) ++ [Pivot] ++ qsort(Right).
The above code could be read as:
(上のコードはこのように読めます)
"qsort of an empty list is an empty list."
"qsort" of a list is the qsort of the left sublist
(of items smaller than the pivot), appended to the pivot, and then the
qsort of the right sublist (of larger items),
where the left and right sublists are defined
by the list comprehensions;
using the first element in the list as
the Pivot.
(空のリストのqsortは空のリスト)
(リストのqsortは、左の(ピボットより小さな要素の)サブリストのqsortをして、そのあとにピボットと、右の(ピボットより大きな要素の)サブリストのqsortを続けるというもの。こで左右のサブリストはリスト内包表現で定義し、リストの最初の要素をピボットとしています)
Erlang: More List Comprehensions (couldn't resist)
(Erlang: もっとリスト内包表現)
Pythagorean Triplets
(ピタゴラス数)
Remember Pythagoras' Theorem?
(ピタゴラスの定理を覚えていますか)
Wikipedia:
A Pythagorean triple consists of three positive integers a, b, and c,
such that a2 + b2 = c2.
(ピタゴラス数は次の関係を満たす3つの自然数からなります)
Generate them using list comprehensions? (これをリスト内包表現を使って生成してみましょう)
pyth(N) ->
Seq = lists:seq(1,N), %% In Perl, @seq = (1..$n); # ;-)
[ {A,B,C} ||
A <- Seq,
B <- Seq,
C <- Seq,
A+B+C =< N,
A*A+B*B == C*C
].
Pythagorean Triplets
(ピタゴラス数)
> pyth(50).
[{3,4,5},
{4,3,5},
{5,12,13},
{6,8,10},
{8,6,10},
{8,15,17},
{9,12,15},
{12,5,13},
{12,9,15},
{12,16,20},
{15,8,17},
{16,12,20}]
Building Servers is Intuitive
(サーバをつくってみると勉強になります)
A Parallel server 並列サーバ
start(Port) ->
{ok, LSock} = gen_tcp:listen(Port, [binary, {reuseaddr, true},
{packet, 4},
{active, true}]),
spawn(fun() -> par_connect(LSock) end).
par_connect(LSock) ->
{ok, Socket} = gen_tcp:accept(LSock),
spawn(fun() -> par_connect(LSock) end),
loop(Socket).
loop(Sock) ->
receive
{tcp, Sock, Bin} ->
io:format("Got: ~p~n", [Bin]),
Reply = Bin,
gen_tcp:send(Sock, term_to_binary(Reply)),
loop(Sock);
{tcp_closed, Sock} ->
io:format("Server socket closed.~n")
end.
Digression into Real-time stuff
(リアルタイムな余談)
Mouse Events
(マウスイベント)
Double-click Problem
(ダブルクリック問題)
- Most GUI systems (including Javascript in a browser)
try to provide a way to tell when a click is a double-click
(Javascriptを含めて、GUIシステムはたいていクリックがダブルクリックかどうか判断できるようにしています)
- But at least one single-click event will be
fired first
(が、まずは少なくともひとつはシングルクリックのイベントを起こす必要があります)
- Single, Single, Double (シングル、シングル、ダブル)
- Sometimes Single, Double (場合によってはシングル、ダブル)
- Is exclusion possible? (除外できる?)
- Only if we are willing to wait. (待つ気があれば)
Double-Click Problem: Perl/GTK+
(ダブルクリック問題: Perl/GTK+)
my $evt_box = Gtk2::EventBox->new;
$evt_box->signal_connect(button_press_event => sub {
my ($widget, $event) = @_;
if ($event->type eq 'button-press') {
print "single click...\n";
} elsif ($event->type eq '2button-press') {
print "double click...\n"
}
});
Double-Click Problem: Perl/GTK+, POE
(ダブルクリック問題: Perl/GTK+, POE)
POE::Session->create(
inline_states => {
_start => \&ui_start,
evt_pressed => \&handle_pressed,
evt_single_click => sub {
print "single click!\n";
},
evt_double_click => sub {
print "double click!\n";
}
}
);
sub handle_pressed {
my ( $kernel, $session, $heap ) = @_[ KERNEL, SESSION, HEAP ];
my $event = $_[ARG1]->[1];
$kernel->alarm_remove(delete $heap->{single_click_alarm});
if ($event->type eq 'button-press') {
$heap->{single_click_alarm} = $kernel->delay_set(evt_single_click => 0.2 );
} elsif ($event->type eq '2button-press') {
$kernel->yield('evt_double_click');
}
}
In Erlang
get_event() ->
receive
{mouse, click} ->
receive
{mouse, click} ->
double_click
after double_click_interval() ->
single_click
end
...
end.
end.
(おわりに)
- Threads are hard; STM may help (スレッドは大変。STMなら楽になるかも)
- Message passing is worth a look (メッセージ私は一見の価値あり)
- Erlang's influence on Java -> Scala (Erlangの影響を受けてJavaからScalaが生まれた)
- Something for Perl too? (Perlの場合は?)
- Thanks! (ありがとうございました)