まだVol.33も正式発売されていないというのに、すでにVol.34の原稿書きにいそしむ今日この頃。実はその記事の一つがHaskellだ。「Powered by Ph.Dな言語の解説を中卒がやるのってどうよ?」と我ながら思うが、自分で言うのもなんだがむしろいい記事に仕上がってきているのを感じる。
Matzにっき(2006-06-13)私:「Haskell難しいですから」
「ええっ?」
というわけで、予告ついでに、HaskellよりRubyの方がずっと難しいことを一つ上げさせていただく。
それは、なんといってもProcオブジェクトだ。
「Rubyの美しくない部分を一つあげよ」と聞いて、真っ先に思い立つのがこれだ。
例えば、logbXをカリー化して表現することを考えてみる。
いづれの電脳言語でも、log()はln()(log natural)として定義されているので、ここではlog2と名付けることにする。あまり美しくないが、Log()とするとhaskellで問題が生じるし、一応atan2()とも整合性がとれるので。
まずはPerl 5で。
sub log2{
my $b = shift;
sub {
my $x = shift;
log($x)/log($b)
}
}
使うときは、こう。
my $lg2 = log2(2); print $lg2->(16);
Perl6だと、もっと美しくかける。
sub log2($b){ sub($x){ log($x)/log($b) } }
my $lg2 = log2(2);
say $lg2.(16)
Pythonだと、こんなか。
import math def log2(b): return (lambda x: math.log(x) / math.log(b) ) # 2.3以降は math.log(x, b) もOKだそうだ lg2 = log2(2) print lg2(16)
いちいちlambdaと言わなければならないところが、Perlより不自然だ。
それでは、Rubyでは?
def log2(b)
return lambda{ |x| log(x) / log(b) }
end
まあ、ちょっとPythonじみているけど、mathをimportしない分よしとしよう。問題はこれを呼び出すときだ。
lg2 = log2(2); p lg2(16);
が動かないのである。
p log2.call(16)
としなければならないのだ。
それで、Haskellはどうかというと、
log2 b x = log x / log b
こんだけ、である。カリー化はデフォルトなのだ。だから型宣言では、
log2 :: (Floating t) => t -> t -> t
と矢印を使う。それであれば
lg2 = log2 2
とした時に、実に直感的に
lg2 :: t -> t
であることが定まる。そしてHaskellは、こういう直感は型推論でよきにはからってくれる。
これは、確かに簡単で直感的だ。直感度で行くと残りはperl, python, rubyといった順序になると思う。
実は、この自動カリー化と型推論は Perl6 でも取り入れられることが決まっている。
sub log2($b,$x){ log($x)/log($b) }
my $lg2 = &log2.assuming(2);
say $lg2.(16)
Haskellに比べるとめんどくさい感じがするが、これは Perl6 があくまでもふだんは手続き型言語のふりをして、必要とあればいつでも関数型に「化ける」というポジションにあるからだ。実は Perl6 は、「スキン」は Ruby から最も多く盗んでいるが、「はらわた」は Haskell から最も多く盗んでいるのだ。
Rubyではこの辺どうしていくのだろうか....
Dan the Multilingual
from math import log
log2 = lambda x:(lambda y: log(y, x))
か、あるいは、
from math import log
def log2(x):
def xlog2(y):
return log(y, x)
return xlog2
のほうが、ちょっとキレイかも………
(全く実の無い話でごめんなさい)