Почему maplist / 3 не использует шаблон?

Предикат maplist / 3 имеет следующую форму

maplist(:Goal, ?List1, ?List2)

Однако очень похожая функция findall / 3 имеет вид

findall(+Template, :Goal, -Bag)

У него есть не только цель, но и шаблон. Я нашел этот шаблон весьма полезным во многих местах и ​​начал задаваться вопросом, почему в maplist / 3 его нет.

Почему у maplist / 3 нет аргумента шаблона, а у findall / 3 есть? В чем существенное различие между этими предикатами?


person Éamonn Olive    schedule 03.01.2018    source источник
comment
Предположим, у maplist/3 действительно есть шаблон. Как это должно повлиять на семантику этого предиката?   -  person mat    schedule 03.01.2018
comment
@mat Я не совсем понимаю, о чем вы спрашиваете. Если бы у maplist / 3 был шаблон, он, скорее всего, имел бы форму maplist(+Template1, +Template2, :Goal, ?List1, ?List2), например findall / 3. Я не уверен, что вы здесь подразумеваете под семантикой.   -  person Éamonn Olive    schedule 03.01.2018
comment
Я имею в виду: не могли бы вы, например, добавить конкретный пример запроса, где вы показываете, как вы будете использовать такой шаблон на практике, или описываете, как это повлияет на ответы?   -  person mat    schedule 03.01.2018


Ответы (3)


Шаблоны, такие как findall/3, setof/3 и bagof/3, представляют собой попытку имитировать правильную количественную оценку с помощью переменных Пролога. В большинстве случаев (и здесь во всех трех случаях) они включают явное копирование этих терминов в шаблоне.

Для maplist/3 такие механизмы не всегда необходимы, поскольку фактическая количественная оценка здесь касается только элементов списков. Как правило, дальнейших изменений не происходит. Вместо использования шаблонов первый аргумент maplist/3 - это неполная цель, которой не хватает двух дополнительных аргументов.

maplist(Goal_2, Xs, Ys).

Если вы настаиваете, вы можете получить именно свою версию шаблона, используя library(lambda):

templmaplist(Template1, Template2, Goal_0, Xs, Ys) :-
   maplist(\Template1^Template2^Goal_0, Xs, Ys).

(Обратите внимание, что я избегаю называть это maplist/5, поскольку это уже определено с другим значением)

В общем, я предпочитаю избегать создания «своих собственных шаблонов», поскольку это так легко приводит к недоразумениям (уже между мной и мной): аргументы не являются чисто реляционными аргументами, которых обычно ожидают. Используя вместо этого (\)/1, локальные переменные несколько лучше обрабатываются и более заметны как особые.

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

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

person false    schedule 04.01.2018

Рассмотрение вашего конкретного примера покажет, почему шаблон не нужен для maplist/3:

В maplist/N и других предикатах более высокого порядка можно использовать каррирование для исправления определенного аргумента.

Например, вы можете написать предикат:

p(Z, X, Y) :-
        Z #= X + Y.

И теперь ваш пример работает точно так, как ожидалось, без необходимости в шаблоне:

?- maplist(p(1), [1,2,3,4], [0,-1,-2,-3]).
true.

Вы можете использовать library(lambda) для динамического изменения порядка аргументов, чтобы сделать это еще более гибким.

person mat    schedule 03.01.2018
comment
Почему тогда для findall используется шаблон? Я понимаю, почему ни не нужен шаблон, мне просто интересно узнать, почему они разные. - person Éamonn Olive; 03.01.2018
comment
maplist/3 имеет очень конкретное значение, где call/N используется с соответствующими парами элементов списка в качестве последних двух аргументов. Но findall/3 допускает любую цель в своем аргументе и вызывает ее без каких-либо дополнительных ограничений или предположений. Как findall/3 вообще узнает, какие аргументы нас интересуют? Таким образом, они должны быть указаны для findall/3, но не должны указываться для maplist/N, где соглашение зафиксировано. - person mat; 03.01.2018

В чем существенное различие между этими предикатами?

findall / 3 (и семейство, setof / 3 и bagof / 3) не могут быть реализованы в чистом Prolog (монотонное подмножество без побочных эффектов), в то время как maplist / N является просто своего рода «макросом», реализующим шаблонный список (ы) visit .

В maplist / N ничего не предполагается об детерминированности предиката, поскольку поток выполнения контролируется шаблоном (ами) списка (ов). findall / 3 это конструктор списка, и очень важна цель terminate, и (я вижу) необходимость указать, что сохранять из каждого успешный вызов цели.

person CapelliC    schedule 04.01.2018