台風一課

捜査一課みたいなノリで.


気合を入れてRubyの勉強中.

うちにあるのはWindowsなので,RDEを入れて,

3.to_s()               → "3":String
3.to_s(1)              → ArgumentError
3.incorrect_method()   → NoMethodError

とかやって,それぞれのエラーを確認した後,いきなりRubyソースコード完全解説とか読み出すわけで,これはかなり特殊な勉強のしかたかもしれない.

まず,パーサを書きたいわけなんだけど,これが面倒っぽい*1.parse.yは見たけど・・・でかっ.読みたくないなあ.そしてこれをocamlyaccで書き直すのが面倒くさい.念のため,誰かが書いてないかGoogleしてみたけど,引っかからない.

どちらかといえばどうでもいいんだけど*2,ocamlyaccでダメだったらCでがんばるしかないんだろうか.それは,やだなあ・・・


引き続き,Rubyについて考える.目標は,Rubyプログラムの型の整合性を保証することだ.ここで,型の整合性がとれているということを次のように定義する.

型の整合性がとれている ⇔ プログラムを実行したときにNoMethodErrorが発生しない*3

ちょっと適当すぎるかもしれないが,まつもとさん自身

しかし、Rubyのような言語にとって継承は単なる実装の共有が目的ですから、興味があるのは「そのクラスのインスタンスが持っているメソッドのリスト」のはずです。

とおっしゃってるので,まあ問題ないだろう.これならsub typingの理論とか,持ち出す必要はなく,単純にメソッドの集合の関係を考えれば良い.

さて,簡単な例から.

def hoge(o)
  o.huga()
end

というメソッドは,引数0のhugaというメソッドを提供するオブジェクトならば,なんでも受け取れる.なので,適当な書式だけど,

hoge : {huga: () -> 'a} -> 'a

みたいな型みたいのになる.ここで,1みたいなhugaというメソッドが実装されていないオブジェクトをhogeに渡そうとすると,型エラーが報告されれば良い.


しかし,簡単なのは上の例くらいのものだった.

def hoge(cond_expr)
  if (cond_expr)
    return 1
  else
    return "a"
  end
end

となると,話は複雑になる.この場合,cond_exprが真なら,

hoge: Boolean -> Integer

だし,偽ならば

hoge: Boolean -> String

になってしまう*4

ていうか,こういうパターンさっきまで考えてなかった.ずぎゃー


ずぎゃーとか言ってても始まらないので,もう少し考えてみる.

そもそも,どういう場合に上のようなコードを書く必要があるのか.パッと思いつくのは,FactoryMethodだ.その場合は問題ない.ifのbodyとelseで,返されるオブジェクトのメソッドの共通部分を取れば良い.

class LionAnimal
  ....
  def lionSpecificMethod()
    print "Gaooo"
  end

  def hoge()
    print "Lion"
  end
end

class FishAnimal
  ....
  def fishSpecificMethod()
    print "Pityan"
  end

  def hoge()
    print "Fish"
  end
end

def newAnimal(type)
  case type
  when "Lion":
    return Lion.new()
  when "Fish":
    return Fish.new()
  end
end

みたいなプログラムでは,newAnimalの返り値はhogeを実装していることは保証できる.FactoryMethodの範疇で考えれば,これだけで問題ない.よかったよかった.

しかし,ここで例えば

def hoge(animal)
  if animal.type="Lion"
    animal.lionSpecificMethod()   #1
  else
    animal.commonMethod()         #2
  end
end

なんてプログラムを考えると,また話はややこしくなる.#1を考えると,animalは,lionSpecificMethodとtypeを実装していなければならないことになる.しかし,#2を考えるとanimalはcommonMethodとtypeを実装していなければならないことになる.


ん?なんか変だぞ.

最初の例で問題にしているのは,メソッドが返すオブジェクトが満たしていることを保証できる条件で,次の例で問題にしているのは,パラメータとして渡されたオブジェクトが保証していないとまずい条件だ.

と,この辺で混乱してきたので,また今度.

*1:研究室で,RubyはLALRで抑えきれなくなったとか脅されたりとか

*2:ダメだったら,メジャーな構文規則だけ採用したサブセットにして,とりあえず考えれば良いわけだから

*3:ちょっと前のMatzにっきでも書かれていたアイディアなんだけど

*4:BooleanとかIntegerとか,適当に解釈してほしい.RubyのFixnumとかBignumとか,考えるのダルい