为什么在未分配新值的情况下更改此引用?

问题描述

我正在使用ocaml 4.10.0,并具有如下定义的功能

type t = (string * bool) list

let test (t:t) : bool * (string * bool) list =
  match t with
  | [] -> (true,[])
  | (s,b)::[] -> (true,t)
  | _ ->
     let rb = ref true in
     let rl = ref t in
     let rec func (t':t) : unit = 
        match t' with
        | [] -> ()
        | (s,b)::tl -> 
           List.iter(
              fun (s',b') -> 
                 if ((s=s') && (b<>b')) then 
                    rb := false;
                    rl := [(s,b);(s',b')]
           ) tl;
           if (!rb<>false) then func tl;
     in func t; 
     (!rb,!rl)

函数应该测试(string * bool)的列表,如果没有不一致的(string * bool)对,则返回(true,原始列表),否则返回(false,不一致的对)。

例如:

test [("a",true);("b",false);("a",true)]应该返回 (true,[("a",true)])

test [("a",false);("b",true)]应该返回 (false,true)])

但是我现在使用的函数部分错误,它将返回:

test [("a",true)]返回 (true,[("b",true)]返回 (false,true)])

我不知道为什么在不调用if语句的情况下rl会发生变化。

解决方法

你有这个:

if ((s=s') && (b<>b')) then 
   rb := false;
   rl := [(s,b);(s',b')]

但是您的缩进有误导性。 then仅控制以下一个表达式。换句话说,这里总是执行第三行。

您可以使用begin/end(或括号)将then中的两个表达式分组:

if ((s=s') && (b<>b')) then
   begin
   rb := false;
   rl := [(s,b')]
   end

这是有人建议您使用自动缩进代码的系统的原因。这样不太可能导致误导性缩进。