Hatena::ブログ(Diary)

下目黒で Scala で x86_64アセンブラを勉強しつつコンパイラを作る日記

2011-12-21

Scalaソースを読んでいて辞めてほしいと思った12機能

えーっと、 https://github.com/joshcough/Compilers このへんのソースを地道に呼んでいる訳ですが、正直、Scala機能をふんだんに使っていて、

やめてくれー!っと思っております

俺は、Scalaマニアじゃないんだ!コンパイラの仕組みを知りたいんだー!なんて思う訳でした。

ということで、辞めてほしいと思った機能をいろいろと書いてみます

1.traitで多重継承っぽくふんだんに使う

class A extends A1 with A2 with A3

とかやめてほしい。どこに何があるか分からないじゃないかー!

っと

2.traitを後付けでバックエンドを切り替えて嬉しいぜ機能

new A with X86Backend

とかなんとかやると、 AにX86Backendの機能が追加されて嬉しいぜ

ってことらしいのだけど、x86しかないんだから、やらんでいいよ、、、と思うのでした。

3. _:* なにこれって感じなんですけど

可変長引数らしいんだけど、なくても何とかなるので使わなくていいだろうという。

3.foldLeft, map

foreachでなんとかしたらいいような気もするけど、覚えれば大丈夫なのだけど、いつも悩むので、これは覚えるべきか。

4. yield

ストリーミングして云々なのは知っているけど、結局何やってるんだっけ?と悩むので使わなくていいんじゃないかと思うのでした。

8.時間計ってくれる関数

timedとかい関数かなにかを使うといい感じに時間を計ってくれるんだけど、これ本質と関係ないしと思いました。

9.S式の読み込み、出力機能

Scalaなら、タプルやら、Listやらあるので、とくにいらないんじゃないかと。

10.パーサ機能

シンタックスエラーをチェックするのは、ちゃんと作る場合は必要だけど、俺はレジスタ割り付けだけ知りたいのでいらないと思うのでした。

11. case classによる、AST表現

これもなくても作れるのでないほうが読むソース短くなって嬉しいと思いました。

12. implicit conversion

new File("a.txt").readとやってファイル読み込めるぜ

っていうことなんですけど、readFile("a.txt")とかい関数で読み込みでいいよって思ったのでした。

と、いうことで、来年は、このソースを呼んでちゃんと把握したら、もっと分かりやすいレジスタ割り付けするプログラムを書きたいと思いました。

nowokaynowokay 2011/12/22 11:01 foldLeft難しいって言ったら怒られる!
でもfoldLeftは実際になにが起こるかほんとわかりづらいと個人的には思ってて、使わなくてすっきり書けるなら使わなくてもいいかなと思ったり。
mapは定番ということで覚えたほうがいいんじゃないでしょうか。

h_sakuraih_sakurai 2011/12/22 14:36 高階関数がだいたい難しい言われるんですよねぇ。
でも、そうも言ってられないんですよね

kmizushimakmizushima 2011/12/23 10:50 ちょっとコメントしますです。本論については、id:xuweiさんが色々書かれているので、それにお任せ(?)することにして、
foldLeftについて。

これを使うのが良いかどうかは相対的な問題で、たとえば、

(a) val total = list.sum
(b) val total = list.foldLeft(0)((x, y) => x + y)

のどちらが読みやすいか(sumはScalaの標準ライブラリで定義されています)と言われると、さすがに(a)だろう
と思います(「合計値を取る」というのがよりわかりやすい)。

しかし、たとえば
(b) val total = list.foldLeft(0)((x, y) => x + y)
(c)
var total = 0
for(e <- list) {
total += e
}

で、(c)を見たら、(b)の方がわかりやすい…と思います。もちろん、foldLeft()を知らない、あるいは知ったばかりの人にとって(b)の方が
「読みにくい」のは当然の話です。ただ、逆に一度foldLeft()の仕様を「理解」すれば、そちらの方が読みやすく感じる…はず。

また、読みやすさ以外の面でも、

・foldLeft()は「必ず停止する」事が(ライブラリがバグって無ければ)保証される
・ループするよりfoldLeft()した方が、型に起因するバグをコンパイル時にチェックしやすい

というメリットはあります。

foldLeft() 対 map() について言えば、前者の方がより汎用的で「力の強い」関数(foldLeft()があればmap()を実装できる)なので、
foldLeft()を使わずにmap()で済むなら、そちらを使うべきだと考えます。

ちなみに、foldLeftはScalaとかの関数型言語の
専売特許というわけでもなく、Smalltalk/Rubyではinject、Perlではreduce、といった形で、いわゆるLL(?)にも普通に入っている
もので、知っておいて損は無い気がします。

h_sakuraih_sakurai 2011/12/24 21:27 Scalaのfoldleftについてだけに限定すると、呼び出す時に左がリストで右が展開する値なので、あれ、どっちが展開されているんだっけと悩んでいたのですが、それがfoldleftfoldRightの違いだと覚えればいいのでしょうね