方法的返回类型不一致

时间:2019-03-07 15:30:01

标签: ocaml

我正在OCaml中编写一个函数,以检查两种类型是否不可统一,如果有两种类型,则将产生一个统一符,或打印适当的消息。 这是类型系统:

type typExp =
  | TypInt
  | TypVar of char
  | Arrow of typExp * typExp
  | Lst of typExp;;

type substitution = (char * typExp) list;;

我编写了一种方法,该方法可以在给定类型替换规则的情况下用类型表达式执行变量替换。

let rec substitute (tau1 : typExp) (v : char) (tau2 : typExp) : typExp =
  match tau2 with
  |TypInt -> TypInt 
  |TypVar q -> (if(q=v) then tau1 else TypVar q)
  |Arrow (q,w) -> Arrow ((substitute tau1 v q), (substitute tau1 v w))
  |Lst q -> Lst (substitute tau1 v q)

;;

let rec applySubst (sigma: substitution) (tau: typExp) : typExp = 
  let reversedList = List.rev sigma in
  match reversedList with
  |(a,s)::w -> applySubst (List.rev w) (substitute s a tau)
  |[]->tau
;;

我使用那些方法来实现统一检查功能,但是,当两种类型不是统一的时,它应该在屏幕上打印一条消息,并且打印方法返回的单位类型不是替代类型。我不知道该如何处理。

let unify (tau1: typExp) (tau2:typExp) : substitution = 
  let rec helper acc t1 t2=
    match t1, t2 with
    | TypInt,TypInt -> acc(*not the problem*)
    | TypInt, TypVar q -> (q,TypInt)::acc
    | TypInt, Arrow (a,b) -> print_string "Not Unifyable" (* aproblem here*)
    | TypInt, Lst a -> print_string "Not Unifyable"
    | TypVar q, TypInt -> (q, TypInt)::acc
    | TypVar q, Arrow (a,s) -> (q,Arrow(a,s))::acc
    | TypVar q, Lst w -> (q, Lst w)::acc 
    | TypVar a, TypVar b ->( if(a=b) then acc else (a,TypVar b)::acc)
    | Arrow(q,w), Arrow(a,s) ->  if (helper [] w s)=[] then [] 
        else helper (helper [] w s) (applySubst (helper [] w s) q) (applySubst (helper [] w s) a)
    | Arrow (q,w), TypInt -> print_string "Not Unifyable"
    | Arrow (q,w), TypVar a -> (a, Arrow(q,w))::acc
    | Arrow (q,w), Lst a -> []
    | Lst q, TypInt -> []
    | Lst q, TypVar a -> (a,Lst q)::acc
    | Lst q, Arrow (s,t) -> []
    | Lst q, Lst w -> helper acc q w 
  in helper [] tau1 tau2

我想知道不使用选项类型,还有另一种方法可以解决这个问题吗?

2 个答案:

答案 0 :(得分:1)

该问题是由于helper的返回类型是list of substitution而导致的,您的某些匹配项未返回此类型,而是返回了单位类型。因此,编译器指出了此错误。

现在,解决此问题的一种方法是在该点引发异常。

 exception NotUnifiable;;

并替换所有类似于:

的行
    | TypInt, Arrow (a,b) -> print_string "Not Unifyable" 

通过:

    | TypInt, Arrow (a,b) -> raise NotUnifiable

以及unify的用法:

    try 
       unify ...the arguments...
    with NotUnifiable -> print "Not unifiable"

但是这样做可能并不是您真正想要的:一旦出现异常,您就停止一切。

答案 1 :(得分:1)

如果我理解您的问题,则您正在尝试确定无法统一时要返回的值。这只是您实施的基本设计决定,因此我认为没有任何人可以给您答案。

您绝对可以将函数的类型更改为substitution option。那是一个很好的干净解决方案。返回值None表示不可能统一。这些情况如下所示:

print_string "Not Unifyable"; None

您也可以针对这种情况提出例外。在某些情况下,这可能是一个非常有效的解决方案,因为它避免为所有成功的结果(以及提取Some值的工作)为substitution分配空间。但是,时间差通常不值得处理异常的额外复杂性(我认为)。

您也可以返回一个空列表。感觉不太干净,因为这将是无效统一的合理结果(我怀疑)。