Есть ли способ написать предикат length/1, используя write/1 для печати результата?

У меня есть задание для школы, я недавно начал изучать Пролог.
Это упражнение (довольно простое):

Напишите на Прологе программу для нахождения длины заданного списка. Например, length([a, b, c, d, e]). должно напечатать 5

Я действительно понятия не имею, как создать предикат length/1, который сделает это за меня. Это код, который у меня есть:

length([],0).
length([_|T],N) :- length(T,X), N is X+1. 

Теперь я спросил своего учителя, как превратить это в предикат length/1, и он сказал мне использовать предикат write/1. Я искал предикат write/1, но не вижу, как это поможет мне написать предикат length/1. Какие-нибудь советы/рекомендации по этому поводу?
Чтобы было ясно, это домашнее задание.


person Kes    schedule 25.11.2015    source источник
comment
Нет никакой хитрости. Предикат length/1 гораздо менее полезен, чем предикат length/2. Обычно вы бы сделали, length([1,2,3], N), write(N), nl. Вы могли бы легко превратить это в предикат length/1, если хотите. Немного смущают принципы, которым они, кажется, учат на курсах по Прологу. Кажется, что они преподают Пролог как тупой и ограниченный императивный язык, а не как простой, но мощный реляционный язык, которым он является.   -  person lurker    schedule 25.11.2015
comment
Хороший комментарий, +1! Раньше я видел это точно так же, пока @repeat не указал мне на одну интересную вещь: если вы посмотрите на людей, которые пренебрежительно преподают и используют Пролог, вы часто увидите, что они очень счастливы, хотя они используют только крошечную часть реальные возможности языка. С тех пор я пришел к несколько иной интерпретации этого: хотя они так много теряют, они уже очень довольны тем немногим, что у них есть! В будущем они, вероятно, будут еще более довольны более общими функциями (ограничениями и т. д.), которые становятся все более широко известными!   -  person mat    schedule 25.11.2015


Ответы (2)


Решение простое: impure(Ls) :- length(Ls, L), write(L)..

Однако это очень плохая идея по нескольким причинам.

Очень важным является то, что вещи, которые появляются только на вашем экране, не могут быть рассмотрены в Prolog!

Таким образом, если вы просто записываете некоторые результаты с помощью write/1, вы не можете запускать автоматические тестовые примеры, чтобы увидеть, действительно ли ваш предикат ведет себя так, как ожидалось. По крайней мере, таким образом написание тестов становится намного сложнее.

Напротив, с исходной, более чистой версией кода (в которой не использовались побочные эффекты) вы можете легко протестировать, например:

?- length([a,b,c], 3).
true.

а также запустить несколько таких тестовых случаев автоматически и использовать Prolog, чтобы увидеть, успешны ли они. Например, пакет из 10 000 тестов может выглядеть так (поиск контрпримеров):

?- between(1, 10_000, L), length(Ls, L),  length([_|Ls], L1), L1 =\= L+1.
false.

Напротив, как проверить нечистый предикат?

?- between(1, 10_000, L), length(Ls, L),  impure([_|Ls])  what now??

Как видите, действительно трудно рассуждать о выводе предиката!

Кроме того, это делает ваш предикат намного менее общим, чем ваша текущая версия! Вы больше не можете использовать нечистую версию в других направлениях. Например, как теперь сгенерировать список заданной длины? Нет возможности поставить длину!

Оставайтесь чистыми людьми и используйте верхний уровень Пролога для получения ответов вместо того, чтобы писать их на экране!

person mat    schedule 25.11.2015

TL;DR: Не надо!

То, что вы хотите, определенно можно сделать на Прологе, но спросите себя: "Должен ли я сделать это так?".

Мой вам совет, как действовать:

  1. Не используйте низкоуровневый API ввода/вывода Пролога (write/1, nl/0, ...), так как он основан на side-effects.

  2. Используйте dcg! Начните с чтения этого прекрасного учебника по Прологу по грамматикам с определенными предложениями.

  3. Ознакомьтесь (и используйте!) с prolog- верхний уровень.

person repeat    schedule 25.11.2015