2016-07-21 1 views
1

私はOCamlを初めて使い、Functorについて学んでいます。Functors - インポートタイプ

utop # module type Foo = sig 
    type t = { 
     foo : int; 
     bar : int; 
    } 
    val create : int -> int -> t 
    val get : t -> int 
end;; 

utop # module FooImpl = struct 
    type t = { 
     foo : int; 
     bar : int; 
    } 
    let create x y = { 
     foo = x; 
     bar = y; 
    } 
    let get w = w.foo 
end;; 

は、今私はFoo型のモジュールで動作し、get機能を置き換えます私のファンクタを定義してみましょう:これまでのところ、私は次のよう持っています。

utop # module Functor (F : Foo) : Foo with type t := F.t = struct 
    let create = F.create 
    let get w = w.bar 
end;; 
Error: Unbound record field bar 

レコードのタイプについてはわかりません。私はそれを定義してみましょう:

utop # module Functor (F : Foo) : Foo with type t := F.t = struct 
    type t = { 
     foo : int; 
     bar : int; 
    } 
    let create = F.create 
    let get w = w.bar 
end;; 
Error: Signature mismatch:                            ...                                Values do not match: 
    val get : t -> int 
    is not included in 
    val get : F.t -> int 

だから、OCamlではtF.tは、実際には同じタイプであることを知りません。だから私はそれを言ってみよう:

utop # module Functor (F : Foo) : Foo with type t := F.t = struct 
    type t = F.t 
    let create = F.create 
    let get w = w.bar 
end;; 
Error: Unbound record field bar 

私は間違って何をしていますか?

答えて

3

フィールド名は、それらのモジュールの範囲に属するものが定義される。たとえば、モジュール内のレコードを定義する場合Foo

module Foo = struct 
    type t = { bar : int; baz : int; quz : int } 
end 

その後、あなたは完全修飾名を使用する必要がFooモジュール、例えば外このフィールドにアクセスするために、パターンでは

let bar_of_foo x = x.Foo.bar 

フィールド名に一致することも修飾することができ、これは次のように上記関数を記述することができます:

let bar_of_foo {Foo.bar} = bar 

あなたが唯一の名前を修飾する必要があり、

let sum_of_foo {Foo.bar; baz; quz} = bar + baz + quz 

最後に、あなたはopenモジュールは、現在のスコープにレコード名を持参することができます:あなたが一度に複数のフィールドにアクセスする必要があるときに、この構文は、便利です。あなたの例のフィールドで

let bar_of_foo x = Foo.(x.bar) 

がファンクタFunctorへのパラメータであるモジュールFで定義されています:あなたは、開口部の影響を局所化するために、ローカルのオープン構文Foo.(expr)を使用することができます。そのため、上記の方法のいずれかを使用してフィールドにアクセスする必要があります(例:

module Functor (F : Foo) : Foo with type t := F.t = struct 
open F 
let create = F.create 
let get w = w.bar 
end 
2

ファンクタを定義であなたの最初の試みは、私は、このようgetを定義した場合私の作品:

let get w = w.F.bar 

ここに私の完全なセッションです:

# module type Foo = sig (... ELIDED...) end;; 
module type Foo = 
    sig 
    type t = { foo : int; bar : int; } 
    val create : int -> int -> t 
    val get : t -> int 
    end 
# module FooImpl = struct (...ELIDED...) end;; 
module FooImpl : 
    sig 
    type t = { foo : int; bar : int; } 
    val create : int -> int -> t 
    val get : t -> int 
    end 
# module Functor (F: Foo) : Foo with type t := F.t = struct 
    let create = F.create 
    let get w = w.F.bar 
end;; 
module Functor : 
    functor (F : Foo) -> 
    sig val create : int -> int -> F.t val get : F.t -> int end 
# module F2 = Functor(FooImpl);; 
module F2 : 
    sig val create : int -> int -> FooImpl.t val get : FooImpl.t -> int end 
# let c1 = FooImpl.create 8 9;; 
val c1 : FooImpl.t = {FooImpl.foo = 8; bar = 9} 
# FooImpl.get c1;; 
- : int = 8 
# let c2 = F2.create 8 9;; 
val c2 : FooImpl.t = {FooImpl.foo = 8; bar = 9} 
# F2.get c2;; 
- : int = 9 
関連する問題