Это не ответ, а просто предложение по тестированию, которое не помещается в комментарии.
Помимо нежелательного дублированного решения, существует также вопрос о том, как проверить предикат. Простым альтернативным решением является использование стандартного предиката ISO Prolog sort/2
и стандартного предиката де-факто length/2
. Альтернативное решение может быть:
cardinality(List, Cardinality) :-
sort(List, Sorted),
length(Sorted, Cardinality).
. Мы можем использовать это альтернативное решение, чтобы определить свойство , которому должно соответствовать ваше решение, что позволяет QuickCheck ваше решение (игнорируя пока нежелательные не -determinism):
property(List) :-
once(crdnlty(List, C)),
sort(List, S),
length(S, C).
Использование реализации QuickCheck, предоставляемой инструментом lgtunit
Logtalk (который вы можете запускать в большинстве систем Prolog; в этом примере я буду использовать GNU Prolog):
$ gplgt
...
| ?- {lgtunit(loader)}.
...
% (0 warnings)
(578 ms) yes
| ?- lgtunit::quick_check(property(+list(integer)), [n(2000)]).
% 2000 random tests passed
(1589 ms) yes
Конечно, QuickCheck может показывать ошибки, но не может доказать их отсутствие. Тем не менее, отличительной особенностью реализации QuickTheck в Logtalk является то, что он пробует тривиальные / угловые случаи для указанных типов перед генерацией случайных значений. Это помогает гарантировать, что случайное тестирование не пропустит очевидные тестовые случаи (как мы проиллюстрируем далее).
Что произойдет, если вместо этого мы протестируем решение, предоставленное Скоттом Хантером?
| ?- lgtunit::quick_check(property(+list(integer)), [n(2000)]).
* quick check test failure (at test 1 after 0 shrinks):
* property([])
no
В На самом деле, его решение не учитывает, что список может быть пустым. Предполагая, что это считается ошибкой, добавьте отсутствующее предложение:
crdnlty([], 0).
Повторное тестирование:
| ?- lgtunit::quick_check(property(+list(integer)), [n(2000)]).
% 2000 random tests passed
(1509 ms) yes