2016-12-14 2 views
5

docs for the Pervasives.compare function утверждают, чтоМожет ли сравнивать возврат ничего, кроме -1, 0 и 1?

compare x y возвращает 0, если x равно y, отрицательное целое число, если x меньше y, и положительное целое число, если x больше, чем y.

Это говорит о том, что может возвращать любое отрицательное или положительное целое число, а не только -1 или 1, чтобы представлять greater- или меньшую-ность. Однако действительно ли это происходит?

Это сделало бы написание кода, как

match String.compare key new_key with 
    | 1 -> Node (left,    insert new_key right, key) 
    | -1 -> Node (insert new_key left, right,    key) 
    | _ -> Node (left,    right,    key) 

гораздо сложнее (с использованием when, наверное?).

Меня особенно интересует String.compare. Взглянув на its implementation, он просто переходит на Pervasives.compare, который, в свою очередь, реализован изначально с использованием external. Не знаю, что он делает.

+1

Я только начал изучать OCaml тоже. Это здорово видеть, что вы публикуете этот тег^_^ – naomik

ответ

3

Мне интересно, почему нельзя использовать обертку @kne, предложенную напрямую. Ваш код будет выглядеть следующим образом:

match String.compare key new_key with 
    | 0    -> Node (left, right, key) 
    | x when x > 0 -> Node (left, insert new_key right, key) 
    | _ (* x < 0*) -> Node (insert new_key left, right, key) 

Это сохраняет вызов функции и не значительно длиннее, чем подход -1/0/1. Кроме того, сравнение часто предоставляется пользователем (см., Например, Set.OrderedType), где ограничение может быть нарушено в любом случае.

+0

Да, это было бы моим решением, но я подумал, не является ли это идиоматичным? Эта конструкция используется в корпоративных проектах ocaml? – Bergi

+0

Я не программирую ocaml уровня предприятия, но сопоставление шаблонов через, когда довольно распространено. –

3

Действительно ли это происходит?

No.

Pervasives.compare реализована изначально с использованием external.

Я думаю, что это относится к compare.c, что делает реализацию string case использованием

#define LESS -1 
#define EQUAL 0 
#define GREATER 1 

mlsize_t len1 = caml_string_length(v1); 
mlsize_t len2 = caml_string_length(v2); 
int res = memcmp(String_val(v1), String_val(v2), len1 <= len2 ? len1 : len2); 
if (res < 0) return LESS; 
if (res > 0) return GREATER; 
if (len1 != len2) return len1 - len2; 

Так, кажется, это действительно может вернуть произвольное целое число строк, как compare "a" "abc" (-2).

Но если мы попробуем в Окамле, этого не произойдет и просто вернется -1. Почему нет?
Поскольку real compare function, подверженной OCaml код делает нормализуют результаты:

CAMLprim value caml_compare(value v1, value v2) 
{ 
    intnat res = compare_val(v1, v2, 1); 
    if (res < 0) 
    return Val_int(LESS); 
    else if (res > 0) 
    return Val_int(GREATER); 
    else 
    return Val_int(EQUAL); 
} 

Так что на самом деле может не возвращать int, кроме этих трех.

6

Ответ сам по себе показывает, что никакие другие значения не могут быть возвращены в текущей реализации. Однако я был бы очень осторожен, чтобы полагаться на это. Поскольку compare не является , зарегистрированным как трехзначным, будущие версии OCaml могут изменить это поведение.

[EDIT, отвечая на комментарий] Для того, чтобы избежать громоздкого различия регистра (как намекнул в вашем первоначально вопросе), вы можете обернуть compare в функцию, которая возвращает три значения типа так:

type comparison = Less | Equal | More 

let my_compare a b = match compare a b with 
| 0 -> Equal 
| c when c>0 -> More 
| _ -> Less 
+0

Да, я полностью согласен. Итак, как будет выглядеть идиоматическое трехстороннее сравнение в Ocaml? – Bergi

+0

Почему в стандартной библиотеке нет такого типа сравнения? – Bergi

Смежные вопросы