Search code examples
tuplesglobal-variablesocamlref

Trying to create a global variable in OCaml


let generateNextAssignList (assignList : (string * bool) list) : (string * bool) list * bool = 
  let carry = ref true in
  let flag = ref true in
  let inc_bools head =
    let (var, boolean) = head in 
    if (boolean = false && !flag = true) then
      (flag := false; carry := false; (var, Bool.not boolean))
    else if (boolean = true && !flag = true) then
      (var, Bool.not boolean)
    else
      (var, boolean) in
  (List.rev (List.map inc_bools (List.rev assignList)), !carry);;

generateNextAssignList [("a", true); ("a", true); ("a", false)];;

I would like to have !carry be false in all cases, unless the list passed to the function is [], or the bool in every tuple in the list is true. So far, when I use the function, it is working properly, but !carry is always true, but is updating inside the function correctly. Is there a way to make it into a global variable that would fix this?


Solution

  • The issue is that !carry is evaluated before the first element of the tuple in

    List.rev (List.map inc_bools (List.rev assignList)), !carry
    

    If you need to enforce the order of side-effect it is better to add an explicit let:

      let result = List.rev (List.map inc_bools (List.rev assignList)) in
      result, !carry
    

    ( Note that there is a gap between your implementation and specification: carry is true if there is a value at the left of a false value in assignList. )

    But it is probably better to avoid references by splitting your algorithm in two:

    • first split the reversed list up to the first false value
    • compute carry according to the number of elements on the left of this first false value
    • create the resulting list:
    let generateNextAssignList assignList =
      let rec reverse_until_first_false rev = function
        | [] -> rev, []
        | (v, false) :: q -> (v,true) :: rev, q
        | (v, true) :: q -> reverse_until_first_false ((v, false) :: rev) q
      in
      let rev, rest = reverse_until_first_false [] (List.rev assignList) in
      let carry = match rest with [] -> true | _ -> false in
      let result = List.rev_append rest rev in
      result, carry