Weird utop behavior - different function's result for the same input?

in bin/main.ml

type 'a rle =
  | One of 'a
  | Many of (int * 'a)

(* Implement the so-called run-length encoding data compression method directly. I.e. don't explicitly create the sublists containing the duplicates *)
let encode lst =
  let rle n s = if n == 0 then One s else Many (n + 1, s) in
  let rec aux n acc = function
    | [] -> []
    | [ x ] -> rle n x :: acc
    | x1 :: (x2 :: _ as tl) when x1 == x2 -> aux (n + 1) acc tl
    | x :: tl -> aux 0 (rle n x :: acc) tl
  in
  List.rev @@ aux 0 [] lst

It is part of a dune project, with local switch on OCaml 5.5.0 .

Now, when function is invoked by

encode ["a";"a";"a";"a";"b";"c";"c";"a";"a";"d";"e";"e";"e";"e"]

as part of project execution (from entry point), I get expected result

[Many (4, a); One b; Many (2, c); Many (2, a); One d; Many (4, e)]

Now, when I call the same function with same argument without any modification in utop,

run with dune utop, I get quite different result:

# #use "bin/main.ml";;
val encode : 'a list -> 'a rle list = <fun>

# encode ["a";"a";"a";"a";"b";"c";"c";"a";"a";"d";"e";"e";"e";"e"];;
- : string rle list =
[One "a"; One "a"; One "a"; One "a"; One "b"; One "c"; One "c"; One "a";
 One "a"; One "d"; One "e"; One "e"; One "e"; One "e"]

I may miss something obvious, but this baffles me.

Care anyone explain how is that possible?

You are using == (physical equality) to compare the elements of the list. The behaviour of physical equality on immutable values (such as strings) is unspecified, and indeed you are seeing that the behaviour is different in bytecode (utop) and in native-code (which you probably used when compiling with Dune).

The solution is to not use physical equality (which is not what you want here in any case), but rather usual structural equality polymorphic operator = or, even better, a type-specific equality operator, such as String.equal.

Cheers,
Nicolas

7 Likes

Yep, this is the case.

Thanks :+1: