2017-01-10 3 views
3

Я очень смущен тем, как CLP работает в Prolog. Мне не только трудно увидеть преимущества (я вижу это в конкретных случаях, но сложно обобщить их), но что еще более важно, я едва ли могу правильно составить рекурсивный предикат. Какая из следующих будет правильной формой в режиме CLP (R)?Правильный способ записи рекурсивных функций в CLP (R) с помощью Prolog

factorial(0, 1). 
factorial(N, F):- { 
    N > 0, 
    PrevN = N - 1, 
    factorial(PrevN, NewF), 
    F = N * NewF}. 

или

factorial(0, 1). 
factorial(N, F):- { 
    N > 0, 
    PrevN = N - 1, 
    F = N * NewF}, 
    factorial(PrevN, NewF). 

Другими словами, я не уверен, когда я должен писать код за пределы ограничений. Для меня первый случай выглядит более логичным, потому что PrevN и NewF принадлежат ограничениям. Но если это правда, мне любопытно посмотреть, в каких случаях полезно использовать предикаты за пределами ограничений в рекурсивной функции.

ответ

4

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

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

Во-первых, я хотел бы коснуться того, что я считаю самым важным в вашем случае:

LP & subseteq; CLP

Это означает, что CLP можно рассматривать как переопределение логического программирования (LP). Следует ли считать надлежащим образом, или, если на самом деле, это даже имеет смысл рассматривать их как обозначающие одну и ту же концепцию, является несколько спорным. По моему личному мнению, логическое программирование без ограничений гораздо труднее понять и гораздо менее полезно, чем с ограничениями. Учитывая, что даже самые первые системы Prolog имели ограничение, такое как dif/2, а также то, что существенные встроенные предикаты, такие как   (=)/2, отлично соответствуют понятию «ограничение», границы, если они вообще существуют, кажутся мне по крайней мере несколько искусственными , что указывает на то, что:

LP & approx; CLP

Как бы то ни было, ключевым понятием при работе с CLP (любого вида) является то, что ограничения доступны в   предикатами, и используются в программах Prolog, как и все другие предикаты.

Таким образом, есть ли у вас цель factorial(N, F) или { N > 0 }, по крайней мере, в принципе, то же самое понятие: Оба означает, что что-то   держит.

Обратите внимание на синтаксис : Принтер CLP (ℛ) ограничения имеют вид { C }, который   {}(C) в префиксной нотации.

Заметим, что цель factorial(N, F): не a CLP (ℛ) ограничение! Не является следующее:

 
?- { factorial(N, F) }. 
ERROR: Unhandled exception: type_error({factorial(_3958,_3960)},...) 

Таким образом, { factorial(N, F) } является не CLP (ℛ) ограничение либо!

Ваш первый пример поэтому не может работать по этой причине один уже. (Кроме того, у вас есть ошибка синтаксиса в пункте голове: factorial (, так оно и не компилирует вообще.)

Когда вы научитесь работать с решателя, проверить предикаты она предоставляет. Например, CLP (ℛ) обеспечивает {}/1 и несколько других предикатов, и имеет специальный синтаксис для постановки отношений,   держать около чисел с плавающей точкой (в данном случае).

Другие решатели предоставляют свои собственные предикатов для описания сущности их соответствующих доменов. Например, CLP (FD) предоставляет (#=)/2 и несколько других предикатов для разбора около целых чисел. dif/2 позволяет рассказать о любой Пролог. И так далее.

С точки зрения программиста, это точно такой же как использование любой другой предикат вашей системы Prolog, будь то встроенный или стеблями из библиотеки. В принципе, это все равно:

Цель как list_length(Ls, L) может быть прочитана как: «Длина списка   Ls является   L

Цель как { X = A + B } может быть прочитана как: число X равно сумме из A и   B. Например, если вы используете CLP (Q), то ясно, что мы говорим о рациональных номерах в этом   корпусе.

В вашем втором примере телом оговорки является конъюнкцией формы (A, B), где A является CLP (ℛ) ограничением, и B является целью формы factorial(PrevN, NewF).

Деловая позиция: CLP (ℛ) ограничение также гол! Проверьте это:

 
?- write_canonical({a,b,c}). 
{','(a,','(b,c))} 
true. 

Таким образом, вы просто используете {}/1 из library(clpr), что один из предикатов его экспорта.

Вы правы, что PrevN и NewFотносятся к ограничениям. Однако factorial(PrevN, NewF) не входит в мини-язык , который CLP (ℛ) реализует для рассуждений по номерам с плавающей запятой. Поэтому вы не можете потянуть этот гол в CLP (ℛ) -специальную часть.

С точки зрения программиста, главной достопримечательностью CLP является то, что он смеси в полностью бесшовно в «нормальной» логикой программирования, до такой степени, что он может на самом деле вряд ли можно отличить вообще от   это: ограничения просто предикаты и записываются как все остальные   голов.

ли вы пометили библиотека предикат «ограничение» или нет вряд ли имеет никакого значения: Все предикаты можно рассматривать как   ограничений, так как они могут только сдерживать ответы, никогда расслабиться их.

Отметьте, что как примеры, которые вы публикуете являются рекурсивными! Это отлично   ОК. Фактически, рекурсивные предикаты, вероятно, будут большинства ситуаций, в которых вы используете ограничения   в будущем.

Однако для конкретного случая факторного, CLP вашей системы Пролога (FD) ограничения, вероятно, лучше   подходят, так как они полностью посвящены рассуждения о   целые.

+0

Благодарим вас за подробный ответ. Я предполагаю, что часть, которую мне трудно найти, - это то, как работает решатель ограничений * внутри * Prolog. Например, учитывая, что второй пример кода, который я дал, верен, моя первоначальная идея о ограничениях была неправильной. Я думал, что блок ограничения был * первым * решен (как первая цель в списке целей), но что он не может содержать какие-либо нерешенные переменные. Другими словами, я не видел, как рекурсивный вызов может быть за пределами/после фигурных скобок, если блок ограничения нуждался в значениях, которые он произвел. –

+0

Основная привлекательность логического программирования в целом заключается в том, что он * в значительной степени освобождает вас от таких процедурных соображений. Особенно, если вы только начинаете изучать Prolog и ограничения, сосредоточьте четкое * декларативное * описание, * независимое * того, как цели упорядочены. Пока вы придерживаетесь чистого и монотонного подмножества Prolog (к которому также относятся все ограничения), вы можете свободно переупорядочить все свои цели и узнать о процедурных аспектах на любом этапе, а также позже. Как это работает внутри Prolog, гораздо труднее понять. Например, как '(=)/2' работает внутри Prolog? – mat

+1

Например, хороший способ прочитать второй пример - сказать: «** Если ** это случай, что« N> 0 », ** и ** это тот случай, когда ... и т. Д., * * тогда ** это так, что 'factorial (N, F)' имеет место. Как вы заказываете ограничения, может иметь процедурный эффект, но не позволяйте этому отвлекать вас от значения предложения и из-за того, что вы можете свободно изменять порядок целей, не влияя на декларативный смысл. – mat