Получение минимального значения списка

Я пытаюсь найти минимальное значение списка (в качестве учебного опыта, поэтому без min).

Мой подход следующий:

minimo([X], X).
minimo([X,Y|Tail], N):-
    (X > Y, minimo([Y,Tail], Y));
    (X <= Y, minimo([X,Tail], X)).

Это дает мне следующую ошибку:

Синтаксическая ошибка: Ожидается оператор

Итак, мои вопросы:

  • Что вызывает синтаксическую ошибку?
  • Я попробую это сам, как только это будет исправлено, если оно действительно возвращает правильное значение, но будет ли это действительно правильным подходом?

Заранее спасибо.


person Trufa    schedule 08.11.2011    source источник


Ответы (3)


В вашей программе есть несколько ошибок:

  1. как указал Джо Леманн, '<='/2 не существует. Должно быть '=<'/2.

  2. когда вы вызываете minimo/2 рекурсивно, вы неправильно строите списки. Вместо [Y,Tail] используйте [Y|Tail]. В противном случае вы получите список со списком в качестве второго элемента.

  3. вы привязываете второй аргумент рекурсивного вызова minimo/2 к Y или X. Вместо этого он должен быть привязан к N. В противном случае ваш N никогда не будет создан.

Вы можете улучшить свою программу, добавив сокращения или используя if-then-else ('->' + ;):

minimo([X], X) :- !.
minimo([X,Y|Tail], N):-
    ( X > Y ->
        minimo([Y|Tail], N)
    ;
        minimo([X|Tail], N)
    ).
person twinterer    schedule 08.11.2011

В дополнение к другим уже опубликованным версиям рассмотрите также версию без if-then-else и с использованием более описательного имени для отношения (которое связывает список с его минимумом):

list_min([L|Ls], Min) :- list_min(Ls, L, Min).

list_min([], Min, Min).
list_min([L|Ls], Min0, Min) :-
    Min1 is min(L, Min0),
    list_min(Ls, Min1, Min).

Такой шаблон называется fold (слева направо), и мы можем записать его эквивалентно, используя `foldl/4:

list_min([L|Ls], Min) :- foldl(min_, Ls, L, Min).

min_(A, B, Min) :- Min is min(A, B).

Пример запроса:

?- list_min([1,0,2], Min).
Min = 0.

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

?- list_min([X,Y], 3).
ERROR: is/2: Arguments are not sufficiently instantiated

Чтобы сделать это правильным решением, используйте ограничения, такие как clpfd и clpq. Например, для решения над целыми числами:

:- use_module(library(clpfd)).

list_min([L|Ls], Min) :- foldl(min_, Ls, L, Min).

min_(A, B, Min) :- Min #= min(A, B).

Это работает во всех направлениях:

?- list_min([X,Y], 3).
X in 3..sup,
3#=min(Y, X),
Y in 3..sup.
person mat    schedule 11.11.2011

Синтаксическая ошибка заключается в том, что меньше или равно в Прологе =‹, а не ‹=.

Я думаю, что этот подход будет работать, но вам действительно следует избегать ; в оговорке. Просто разделите его на два предложения.

Также я думаю, что вы хотите сделать что-то вроде [X|Tail] в рекурсии, а не [X,Tail]

person Joe Lehmann    schedule 08.11.2011
comment
=< похоже исправил, спасибо. Но теперь у меня есть эта ошибка: ERROR: >/2: Arithmetic: []/0' не является функцией`` и когда я разделяю ее на две части, я получаю: - minimo([1,2,3],X). ERROR: >/2: Arithmetic: `[]/0' is not a function Exception: (8) minimo([[3], []], [3]) ? Спасибо! +1 - person Trufa; 08.11.2011