The main reason is that the first version is more powerful than the second. The equality operator has the following type, which will constrain the type signature of the first version:
$ sml
Standard ML of New Jersey (64-bit) v110.99.2 [built: Thu Sep 23 13:44:44 2021]
- op =;
val it = fn : ''a * ''a -> bool
The ''a
constraint propagates to the enclosing function definition.
The second version doesn't make use of that operator because it doesn't need to, it only needs to look at the shape of the list, not its constituent elements. We can desugar it to make this more obvious:
fun isEmpty list =
case list of
| nil => true
| _ :: _ => false
It's clear here that it doesn't care about the elements, whereas the other does care, potentially, even if it doesn't in your particular case. For example:
fun isPalindrome list =
list = List.rev list