【问题标题】:Functor compilation issue: Signature mismatch: Modules do not match函子编译问题:签名不匹配:模块不匹配
【发布时间】:2012-04-20 04:14:04
【问题描述】:

首先是代码:

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

我不明白的是更具体的类型如何不包含在更一般的类型中?

【问题讨论】:

    标签: ocaml functor


    【解决方案1】:

    报错信息其实挺准确的:

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

    MyFSM 函子需要一个模块参数,除其他外,该参数应包含类型为 'a bexp -&gt; bool 的函数 eval_exp。这意味着给定一个'a bexp 类型的值来whatever 选择'a,该函数应该产生一个bool 类型的值。但是,您提供的模块包含一个仅针对'a一个特定 选择执行此操作的模块,即'a 是模块@ 中的boolean 类型987654331@.

    这个最快的解决方法是将您的签名 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 -&gt; bool 确实比boolean bexp -&gt; bool 更通用,但实际上并非如此。如果CA 更通用并且BD 更通用,则认为函数类型A -&gt; B 比函数类型C -&gt; D 更通用:

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

    注意前提中CA的“翻转”。我们说函数空间构造函数... -&gt; ... 在其参数位置是逆变(相对于在其结果位置是协变)。

    直观地说,如果一个类型包含更多的值,它就会比另一个更通用。要了解为什么函数空间构造函数的参数位置是逆变的,请考虑针对某些类型 AC 的函数 f 类型为 A -&gt; C。现在,考虑一个比A 更一般的类型B,即A 中的所有值也在B 中,但B 包含一些不在A 中的值。因此,至少有一个值b 可以分配类型B,但不能分配类型A。它的类型告诉我们f 知道如何对A 类型的值进行操作。但是,如果我们(错误地!)从A &lt;: B 得出A -&gt; C &lt;: B -&gt; C,那么我们可以使用f,就好像它具有B -&gt; C 类型一样,因此,我们可以将值b 作为f 的参数。但是b 不是A 类型,f 只知道如何对A 类型的值进行操作!

    显然,... -&gt; ... 在参数位置的协方差不起作用。要查看逆变确实起作用,请考虑相同的类型 ABC,现在还要考虑类型为 B -&gt; C 的函数 g。也就是说,g 知道如何对B 类型的所有值进行操作。函数空间构造函数在其参数位置的逆变使我们得出结论,g 也可以安全地分配给类型A -&gt; C。我们知道A 中的所有值也在B 中,g 知道如何处理所有B 这没有问题,我们可以安全地将A 中的值传递给g

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-23
      • 2020-10-08
      • 2014-02-09
      • 1970-01-01
      • 2013-02-28
      • 1970-01-01
      相关资源
      最近更新 更多