2

最初のコード:

module Boolean = struct
  exception SizeMismatch
  type boolean = T | F | Vec of boolean array 

  let to_bool v = match v with 
    T -> true
  | F -> false 
  | _ -> raise SizeMismatch
end

module Logic = struct
  type 'a var_t = { name: string; mutable value: 'a }
  type 'a bexp  = Const of 'a
  |             Var of 'a var_t

  let eval exp = match exp with
    Const x -> x
  | Var x   -> x.value

  let make_var s v = { name = s; value = v }
  let set v n = v.value <- n
  let get_var_name v = v.name
  let get_var_val  v = v.value
end

module type EXP =
  sig
    type  'a var_t
    type  'a bexp
    val eval_exp     : 'a bexp -> bool
    val get_var_name : 'a var_t -> string
    val get_var_val  : 'a var_t -> 'a
  end

module LogicExp = 
  struct
    include Logic
    let eval_exp exp = Boolean.to_bool (Logic.eval exp)
  end

module FSM ( Exp : EXP ) = 
  struct
    let print_var v = Printf.printf "%s = %d\n" (Exp.get_var_name v)
    (Exp.get_var_val v)

  end

module MyFSM = FSM(LogicExp) 

let myvar = Logic.make_var "foo" 1;;

MyFSM.print_var myvar ;;

コンパイルすると、次のエラーが発生します。

File "test.ml", line 57, characters 19-27:
Error: Signature mismatch:
   Modules do not match:
     sig
       type 'a var_t =
         'a Logic.var_t = {
         name : string;
         mutable value : 'a;
       }
       type 'a bexp = 'a Logic.bexp = Const of 'a | Var of 'a var_t
       val eval : 'a bexp -> 'a
       val make_var : string -> 'a -> 'a var_t
       val set : 'a var_t -> 'a -> unit
       val get_var_name : 'a var_t -> string
       val get_var_val : 'a var_t -> 'a
       val eval_exp : Boolean.boolean Logic.bexp -> bool
     end
   is not included in
     EXP
   Values do not match:
     val eval_exp : Boolean.boolean Logic.bexp -> bool
   is not included in
     val eval_exp : 'a bexp -> bool

私が理解していないのは、より具体的なタイプがより一般的なタイプにどのように含まれていないのかということです。

4

1 に答える 1

5

エラーメッセージは実際には非常に正確です。

Values do not match:
  val eval_exp : Boolean.boolean Logic.bexp -> bool
is not included in
  val eval_exp : 'a bexp -> bool

MyFSMファンクターは、とりわけ、eval_expタイプの関数を含む必要があるモジュール引数を期待します'a bexp -> bool。つまり、関数の選択にタイプの値が与えられると、タイプ'a bexpが生成されます。ただし、特定の1つの選択肢、つまりモジュールのタイプがである場合にのみこれを実行する関数を含むモジュールを提供しています。'abool'a'abooleanBoolean

この最も簡単な修正は、署名EXPを次のように定義することです。

module type EXP =
  sig
    type  b  (* added *)
    type  'a var_t
    type  'a bexp
    val eval_exp     : b bexp -> bool  (* changed *)
    val get_var_name : 'a var_t -> string
    val get_var_val  : 'a var_t -> 'a
  end

これでeval_exp、固定型のブール式を操作して、次のbように定義LogicExpします。

module LogicExp =
  struct
    type b = Boolean.boolean  (* added *)
    include Logic
    let eval_exp exp = Boolean.to_bool (Logic.eval exp)
  end

に修正bされるようにBoolean.boolean

これらの変更を実装すると、コードがコンパイルされます。

それでは、「より具体的なタイプがより一般的なタイプにどのように含まれないのか」という質問を見てみましょう。'a bexp -> boolこれは、それが実際により一般的であることを前提としていboolean bexp -> boolますが、実際にはそうではありません。関数型は、関数型よりも一般的であり、次よりも一般的である場合A -> B、関数型よりも一般的であると見なされます。C -> DCABD

A <: C        D <: B
--------------------
  C -> D <: A -> B

構内の「反転」に注意してくださいC。関数空間コンストラクターは、引数の位置が反変である(結果の位置が共変である)A言います。... -> ...

直感的には、より多くの値が含まれている場合、タイプは別のタイプよりも一般的です。関数空間コンストラクターが引数の位置で反変である理由を理解するために、いくつかの型とfの型の関数を考えてみましょう。ここで、より厳密に一般的な型を考えてみましょう。つまり、のすべての値もにありますが、にない値がいくつか含まれています。したがって、タイプを割り当てることができる値は少なくとも1つありますが、タイプを割り当てることはできません。そのタイプは、タイプの値を操作する方法を知っていることを示しています。ただし、それから(誤って!)結論を出す場合は、タイプがあるかのように使用できます。A -> CACBAABBAbBAfAA <: BA -> C <: B -> CfB -> Cしたがって、値bを引数として。に渡すことができますf。しかし、タイプでbはなく、タイプの値を操作する方法しか知りません!AfA

明らかに、... -> ...引数位置の共分散は機能しません。共変性が機能することを確認するには、同じ型、、を検討し、次にABの関数Cも検討します。つまり、タイプのすべての値を操作する方法を知っています。引数の位置にある関数空間コンストラクターの共変性により、タイプを安全に割り当てることもできると結論付けることができます。のすべての値もにあり、これらすべてを処理する方法を知っているので、問題は発生せず、値をに安全に渡すことができます。gB -> CgBgA -> CABgBAg

于 2012-04-20T04:45:07.670 に答える