4

メソッドの再定義で遊んでいたところ、次のばかげた例が見つかりました。

class a =
object 
    method get (x : a) = x
end

class b =
object
    inherit a
    method get (x : b) = x
end

私は、b クラスの get メソッドが ab を受け取り、ab を返すことを明確に指定していますが、メソッド シグネチャは a -> a です。そして、私が (new b)#get(new a) を実行すると、彼はとても喜んでくれます。その後、私は何かばかげたことを追加しました:

class a =
object 
    method get (x : a) = x
end

class b =
object
    inherit a
    method get (x : b) = x#foo(x)
    method foo (x : a) = x
end

そして、私は得るError: This expression has type b It has no method foo

一体何が起こっているのですか?

4

1 に答える 1

5

最初の例をまず取り上げます。OCaml には、名目上の型付けではなく、オブジェクトの構造的な型付けがあります。つまり、オブジェクトの型は、そのメソッド (およびその型) によって完全に決定されます。したがって、クラスabは実際には同じ型です。

$ ocaml
        OCaml version 4.00.0

# class a = object method get (x: a) = x end;;
class a : object method get : a -> a end
# class b = object inherit a method get (x: b) = x end;;
class b : object method get : a -> a end
# let a0 = new a;;
val a0 : a = <obj>
# let b0 = new b;;
val b0 : b = <obj>
# (a0: b);;
- : b = <obj>
# (a0: a);;
- : a = <obj>
# (b0: a);;
- : a = <obj>
# (b0: b);;
- : b = <obj>
# 

(ここで示そうとしているのは、a0andの両方b0が typea typeであることbです。)

get2 番目の例では、メソッドに新しい型を与えようとしていると言えます。OCaml でメソッドをオーバーライドする場合、パラメーターと戻り値の型は親クラスと同じである必要があります。

エラーメッセージは残念です。私の推測では、コンパイラは type が typebの別の名前であるとあなたを信じていますa

OCaml の強みの 1 つは、型を推論することです。in class: bのパラメータの for を省略すると、代わりに次のエラーが発生します。getb

This expression has type a. It has no method foo

aこれは、パラメーターの型が必要であることを示している (私が思うに) という点で、もう少し役に立ちます。

余談 (すみません): 主流の OO 言語から OCaml の OO 部分にたどり着いた場合、奇妙に感じるかもしれません。しかし、最初に OCaml の FP 部分を学ぶと、なぜすべての主流の OO 言語がこれほど多くの間違いを犯すのか不思議に思うかもしれません :-)。(確かに、すべてはトレードオフであり、計算を構造化する唯一の正しい方法はありません。しかし、OCaml の OO サブシステムはかなり印象的なことを行っています。)

于 2013-05-23T01:57:16.400 に答える