SMLNJ Оператор сортировки вставками и операнд не согласуются с ошибкой

Я делаю код сортировки вставки в SML, вот он

fun compare(x:real, y:real, F) = F(x, y);
fun isEqual(x:real, y:real) = ((x <= y) andalso (x >= y));

fun rinsert(x: real, [], F) = [x]
    |rinsert(x, (y::ys), F) =
    if isEqual(x, y) then rinsert (x, ys, F)
    else if compare(x, y, F) then x::y::ys
            else y::(rinsert (x, ys, F));

fun rinsort([], F) = []
    |rinsort(x::xs, F) = rinsert(x, (rinsort(xs, F), F));

Однако при запуске я получаю эту ошибку

val isEqual = fn : real * real -> bool                                                                                                                                                               
val rinsert = fn : real * real list * (real * real -> bool) -> real list                                                                                                                             
stdIn:12.27-12.58 Error: operator and operand don't agree [tycon mismatch]                                                                                                                           
  operator domain: real * real list * (real * real -> bool)                                                                                                                                          
  operand:         'Z * ('Y list * 'X)                                                                                                                                                               
  in expression:                                                                                                                                                                                     
    rinsert (x,(rinsort (<exp>,<exp>),F))

Я понимаю, что rinsort неправильно вызывает rinsort, но не знаю, как это исправить.


person small502    schedule 07.07.2017    source источник
comment
Сколько аргументов принимает rinsert? Со сколькими вы звоните?   -  person melpomene    schedule 07.07.2017
comment
rinrinrt принимает три аргумента: вещественное число, список и оператор (например, op‹). Это должно быть только вызов трех   -  person small502    schedule 08.07.2017
comment
Я не понимаю, что вы имеете в виду под это должно вызывать только троих. Посмотрите на код. Посчитайте аргументы. Сколько их там?   -  person melpomene    schedule 08.07.2017
comment
Вау, это была ужасная оплошность с моей стороны, спасибо, приятель. Теперь работает нормально   -  person small502    schedule 08.07.2017


Ответы (2)


Если это может быть полезно, это пример того, как ваш код должен работать с areal list:

fun compare(x:real, y:real, F) = F x y;
fun isEqual(x:real, y:real) = ((x <= y) andalso (x >= y));

fun rinsert(x: real, [], F) = [x]
    |rinsert(x, (y::ys), F) =
    if isEqual(x, y) then rinsert (x, ys, F)
    else if compare(x, y, F) then x::y::ys
            else y::(rinsert (x, ys, F));

fun rinsort([], F) = []
    |rinsort(x::xs, F) = rinsert(x, rinsort(xs, F), F);

val funcComp = fn r1 : real => fn r2 : real => if r1 < r2 then true else false;
val l : real list = [1.0, 3.8, 5.6, 3.8, 4.4, 5.6, 6.3, 5.5, 4.6, 8.1];
val b = rinsort(l, funcComp);
person Marco Luzzara    schedule 07.07.2017
comment
if r1 > r2 then false else true лучше выражается как r1 <= r2. - person Simon Shine; 12.07.2017
comment
Да, но не совсем так, потому что isEqual уже проверяет их равенство. В любом случае ваш вариант конечно лучше для понимания. - person Marco Luzzara; 12.07.2017
comment
Не стоит так сравнивать реалы. Вас может заинтересовать Почему я не могу сравнивать вещественные числа в Standard ML? Рассмотрите возможность использования Real.== или теста эпсилон. - person Simon Shine; 13.07.2017

Некоторые общие отзывы:

  • Функция compare служит только для переключения порядка аргументов F, поэтому вы можете просто обратиться к самой F.

  • Функция isEqual немного плохая. Поскольку reals не являются типами равенства в SML по какой-то причине, постарайтесь не сравнивать их так. Оказывается, для сортировки реалов нужно только <=, а не =.

  • Функция rinsert имеет строгие аннотации типа : real, которые не нужны, поскольку ваша сортировка вставками, принимая оператор сравнения F в качестве параметра, также может быть универсальной (полиморфной).

  • Возможно, вы захотите назвать параметр F как-то более описательно, например, cmp, leq или как-то так, что напоминает вам о его назначении.

Вот пример того, как можно сделать функцию сортировки вставками:

fun sort leq xs =
    let fun insert (x, []) = [x]
          | insert (x, y::ys) =
              if leq (x, y)
              then x::y::ys
              else y::insert (x, ys)
    in List.foldl insert [] xs
    end

Он имеет тип ('a * 'a -> bool) -> 'a list -> 'a list. Это сравнимо, например, с Встроенная функция ListMergeSort.sort SML/NJ. Я выбрал sort как каррированный, поскольку вы можете захотеть специализировать его с помощью применения частичных функций, например,

val realsort = sort (op <=) : real list -> real list
val stringsort = sort (op >) : string list -> string list

но я позволил встроенной вспомогательной функции insert быть некаррированной, так как List.foldl принимает функцию с типом ('a * 'b -> 'b), т. е. кортеж (x, ys), и возвращает модифицированный ys со вставленным x.

Вы можете рассмотреть, какие свойства могут проверить, что ваша функция выполняет сортировку. Одним из свойств может быть то, что все элементы списка в отсортированном списке находятся в порядке, указанном оператором сравнения leq.

fun sorted_prop _ [] = true
  | sorted_prop _ [_] = true
  | sorted_prop leq (x::y::xs) = leq (x, y) andalso sorted_prop leq (y::xs)

Другим свойством может быть то, что каждый элемент в несортированном списке существует в отсортированном списке. Последнее свойство может быть трудно проверить, если вы не предполагаете, что x имеет тип равенства (''a). Но вы могли бы сделать это специально в тесте.

person Simon Shine    schedule 13.07.2017