Более простой способ получить «уникальные» привязки? - PullRequest
0 голосов
/ 18 мая 2018

Извините, если моя терминология выключена.Долгосрочный (40 лет? Ой ...) императивный программист, балующийся функционалом, проводящий сегодня утром некоторое время, пытаясь быть более серьезным в отношении декларативного.Пройдя через учебный сайт, решил попробовать «кроссворд» в упражнении 2.4 здесь: http://www.learnprolognow.org/lpnpage.php?pagetype=html&pageid=lpn-htmlse7

Я понял, но это кажется нелепо неуклюжим.Вот мое решение для новичков:

word(astante,  a,s,t,a,n,t,e).
word(astoria,  a,s,t,o,r,i,a).
word(baratto,  b,a,r,a,t,t,o).
word(cobalto,  c,o,b,a,l,t,o).
word(pistola,  p,i,s,t,o,l,a).
word(statale,  s,t,a,t,a,l,e).

crossword(V1,V2,V3,H1,H2,H3):-
    word(V1,V1a,V1b,V1c,V1d,V1e,V1f,V1g),
    word(V2,V2a,V2b,V2c,V2d,V2e,V2f,V2g),
    word(V3,V3a,V3b,V3c,V3d,V3e,V3f,V3g),
    word(H1,H1a,H1b,H1c,H1d,H1e,H1f,H1g),
    word(H2,H2a,H2b,H2c,H2d,H2e,H2f,H2g),
    word(H3,H3a,H3b,H3c,H3d,H3e,H3f,H3g),
    V1b = H1b,
    V1d = H2b,
    V1f = H3b,
    V2b = H1d,
    V2d = H2d,
    V2f = H3d,
    V3b = H1f,
    V3d = H2f,
    V3f = H3f,
    not(V1 = V2),
    not(V1 = V3),
    not(V1 = H1),
    not(V1 = H2),
    not(V1 = H3),
    not(V2 = V3),
    not(V2 = H1),
    not(V2 = H2),
    not(V2 = H3),
    not(V3 = H1),
    not(V3 = H2),
    not(V3 = H3),
    not(H1 = H2),
    not(H1 = H3),
    not(H2 = H3).

Это работает.кроссворд даст мне две возможные раскладки (в конце концов, головоломка симметрична).Но даааа ...

Некоторая неуклюжесть только потому, что я только начал, поэтому я не чувствую, как пометить привязки как "все равно" (1-й, 3-й,Например, 5-я и 7-я буквы слов совершенно не имеют значения).Но что меня действительно раздражает, так это то, что в конце нужно вставить треугольную матрицу «не дублируйте никакие привязки».Эта проблема продолжает возникать (более ранняя проблема с игрушками - любовь (A, B) и ревность (X, Y)), и если вы допустите X = Y, то все, кто уводит отношения любви, утверждают, что ревнуют себя (что я вижу кого-тоеще несколько лет назад боролся с остальным: Получите уникальные результаты с помощью Пролога )), но в этом руководстве этот вопрос не рассматривается.Он даже еще не сказал мне о «нет» - мне пришлось копаться в другом месте, чтобы получить это, что привело к вполне обоснованным вопросам «ну, какого« неравного »вы хотели?», Которым я являюсьв настоящее время не готовы ответить.Но я отвлекся ...

Мне непостижимо, что именно так это и делается в реальном коде.Комбинаторно, это смешно.И кажется, что это нарушает (или, по крайней мере, изгибает) принцип наименьшего удивления.Без ограничений на уникальность существует огромное количество решений, которые просто устанавливают V1 = H1, V2 = H2, V3 = H3.Полагаю, я мог бы только запретить их, но реальное решение должно заключать в себе все ограничения.

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

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

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

Ответы [ 2 ]

0 голосов
/ 19 мая 2018

Но то, что действительно меня сейчас раздражает, так это то, что в конце нужно вставить треугольную матрицу «не дублируйте никакие привязки».

Мы можем получить лучшеерешение с предикатом all_dif/1 отсюда: https://stackoverflow.com/a/47294595/4391743

all_dif([]).
all_dif([E|Es]) :-
   maplist(dif(E), Es),
   all_dif(Es).

Этот предикат принимает список элементов, которые отличаются друг от друга.Пока не беспокойтесь о том, чтобы не понять его, вы можете пока рассматривать его как черный ящик.

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

crossword(V1,V2,V3,H1,H2,H3):-
    ... % unchanged code here
    all_dif([V1, V2, V3, H1, H2, H3]).

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

Я не чувствую, как пометить привязки как "не волнует "(например, 1-я, 3-я, 5-я и 7-я буквы слов совершенно не имеют значения).

Это действительно очень важный вопрос!А Пролог должен предупредить вас о переменных, которые вы используете только один раз (так называемые "одиночные"), потому что они являются частым источником ошибок:

Singleton variables: [V1a,V1c,V1e,V1g,V2a,V2c,V2e,V2g,V3a,V3c,V3e,V3g,H1a,H1c,H1e,H1g,H2a,H2c,H2e,H2g,H3a,H3c,H3e,H3g]

Вы явно помечаете переменную как "все равно", даваяэто имя, начинающееся с символа подчеркивания _, или просто с именем _ в целом.Различные вхождения _ помечают разные переменные "все равно".Таким образом, мы получаем:

crossword(V1,V2,V3,H1,H2,H3):-
    word(V1,_,V1b,_,V1d,_,V1f,_),
    word(V2,_,V2b,_,V2d,_,V2f,_),
    word(V3,_,V3b,_,V3d,_,V3f,_),
    word(H1,_,H1b,_,H1d,_,H1f,_),
    word(H2,_,H2b,_,H2d,_,H2f,_),
    word(H3,_,H3b,_,H3d,_,H3f,_),
    V1b = H1b,
    V1d = H2b,
    V1f = H3b,
    V2b = H1d,
    V2d = H2d,
    V2f = H3d,
    V3b = H1f,
    V3d = H2f,
    V3f = H3f,
    all_dif([V1, V2, V3, H1, H2, H3]).

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

Это оставляет нам задачу удалить все эти уравнения.Общий совет по Прологу: За исключением, может быть, иногда по соображениям наглядности, никогда не нужно писать уравнение вида Var1 = Var2, где обе стороны являются переменными.Просто используйте одно и то же имя для обеих переменных во всем предложении, и вы получите один и тот же результат!

Так что давайте заменим V1b и H1b на одну и ту же переменную с именем A, V1d и H2b по той же переменной B и т. Д.:

crossword(V1,V2,V3,H1,H2,H3):-
    word(V1,_,A,_,B,_,C,_),
    word(V2,_,D,_,E,_,F,_),
    word(V3,_,G,_,H,_,I,_),
    word(H1,_,A,_,D,_,G,_),
    word(H2,_,B,_,E,_,H,_),
    word(H3,_,C,_,F,_,I,_),
    all_dif([V1, V2, V3, H1, H2, H3]).

Это эквивалентно вашему первоначальному решению и, я надеюсь, довольно дружественному для новичков.

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

0 голосов
/ 18 мая 2018

По моему мнению, упражнение настраивает вас на неудачу .

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

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

Я могу заверить вас: То, что вы делаете, конечно, не необходимо при программировании на Прологе.

Итак, не позволяйте ни одной книге отвлекать вас от языка.

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

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

words(Ws) :-
        Ws = [[a,s,t,a,n,t,e],
              [a,s,t,o,r,i,a],
              [b,a,r,a,t,t,o],
              [c,o,b,a,l,t,o],
              [p,i,s,t,o,l,a],
              [s,t,a,t,a,l,e]].

Конечно, вы можете легко получить такое явное (иногда называемое пространственное ) представление автоматически, используя all-solutions предикатов, таких как findall/3.

Ключевой предикат, который я сейчас представляю, позволяет связать слово в этом представлении с каждой секундной буквой:

word_evens([_,A,_,B,_,C,_], [A,B,C]).

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

Теперь все решение, используя предикаты permutation/2 и transpose/2, который вы можете найти как библиотечные предикаты в вашей системе Prolog, или легко реализовать самостоятельно:

solution(Ls) :-
        Ls = [V1,V2,V3,H1,H2,H3],
        words(Ws),
        Ws = [First|_],
        maplist(same_length(First), Ls),
        maplist(word_evens, [H1,H2,H3], Ess),
        transpose(Ess, TEss),
        maplist(word_evens, [V1,V2,V3], TEss),
        permutation(Ws, Ls).

Пример запроса и два решения:

?- solution(Ls).
Ls = [[a, s, t, a, n, t, e], [c, o, b, a, l, t, o], [p, i, s, t, o, l|...], [a, s, t, o, r|...], [b, a, r, a|...], [s, t, a|...]] ;
Ls = [[a, s, t, o, r, i, a], [b, a, r, a, t, t, o], [s, t, a, t, a, l|...], [a, s, t, a, n|...], [c, o, b, a|...], [p, i, s|...]] ;
false.

По крайней мере, maplist/2 должно быть доступно в вашем Прологе, и same_length/2 легко определить, если ваша система не предоставляет его.

Если вы действительно хотите выразить неравенство терминов, используйте .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...