Извлечение списка элементов между двумя значениями в списке - пролог - PullRequest
2 голосов
/ 29 марта 2019

Скажем, у меня есть уникальный список длиной 9 значений от 1 до 9 включительно в случайном порядке (например, судоку), и я хочу извлечь подсписок элементов, которые встречаются между значениями 1 и 9 (эксклюзив). IE: between1and9([1,3,5,4,2,9,7,8,6],[3,5,4,2]) должно быть истинным.

В данный момент я пытаюсь использовать flatten/2, но мне не везет. Вот моя текущая тактика (при условии, что я заставлю List ins 1..9, maplist(all_distinct, List), length(List, 9) в другом месте поддерживать порядок здесь / разделение проблем):

between1and9(List,Between) :-
  flatten([_,[1],Between,[9],_], List);
  flatten([_,[9],Between,[1],_], List).

Эта версия не работает, хотя, когда 1 или 9 находятся в первой или последней позиции в List, или если они смежны в пределах List. between1and9([_,1,9,_,_,_,_,_,_],[]) верно, но between1and9([_,1,9,_,_,_,_,_,_],_) неверно (и не удается, когда я пытаюсь использовать его в качестве ограничения для решения более крупной проблемы.)

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

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

Я могу учесть крайние случаи (каламбур), сопоставив каждую перестановку с дизъюнкциями (то есть: flatten([_,1,B,9,_],L);flatten([_,9,B,1,_],L);flatten([_,1,B,9]);flatten..., и учесть Промежуточное звено как пустой список с: \*above permutations on flatten*\; ( Between = [], (\*permutations for either edge and 1/9*\) )

Но это, кажется, делает уже давно продуманное решение (всего 10 перестановок сглаживания) еще хуже (18), поэтому у меня есть два (сильно связанных) вопроса:

  1. Если бы я мог сделать следующее:

    between1and9(L,B) :-
      ( ( X = 1, Y = 9 ); ( X = 9, Y = 1 ) ),
      ( ( Z1 = _; Z1 = [] ), ( Z2 = _ ; Z2 = [] ) ),
      ( B = _; B = [] ),
      flatten([Z1,X,B,Y,Z2],L).
    

    Мне не пришлось бы вручную печатать каждую перестановку совпадений для flatten. К сожалению, это и несколько его вариантов в одностороннем порядке провалились. Я пропускаю что-то очевидное здесь? (Я подозреваю приоритет оператора, но я пробовал несколько разных версий.)

  2. Или я делаю это совершенно неправильно? Документация flatten/2 предполагает, что в большинстве случаев это анти-паттерн, есть ли более прологичный способ решения этой проблемы? Учитывая все подводные камни, которые я осознаю, проходя через это, я почти уверен, что есть.

(Извините, я до боли осознаю, что большая часть терминологии, которую я использую для описания вещей в этом, вероятно, очень неправильная, я только немного знаком с предикатной / формальной логикой и гораздо более привык к описанию программирование типа потока управления. Несмотря на то, что я достаточно хорошо понимаю логическое программирование на практике, я все еще изо всех сил пытаюсь найти язык, чтобы говорить об этом, я исправлю этот вопрос с любыми поправками, которые получу.)

Некоторые предыстории: я новичок в прологе и проверяю свое понимание, пытаясь расширить один из множества решателей судоку, чтобы решить странное разнообразие судоку, которое я нашел в некоторых головоломках, которые я распечатал много лет назад, где вам показывают сумма всех чисел, которые появляются между 1 и 9 в каждой строке или столбце в качестве дополнительной подсказки, это своего рода смесь судоку и пикросса. Решатель в его нынешнем виде находится на swish: SumSudoku (swish) . Хотя это может быть беспорядок, когда вы добираетесь до него.

* Следующее задание: есть ли прологическая версия слова «питон?»

1 Ответ

2 голосов
/ 29 марта 2019

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

Для случая «1 предшествует 9» вы должны написать:

between_1_and_9(List, Sublist) :-
    append(_, [1|Rest], List),
    append(Sublist, [9|_], Rest).

Вам нужно поменять местами 1 и 9 для случая «9 предшествует 1».

Это также оставляет «ложную точку выбора» (спасибо @PauloMoura за комментарий).Не забудьте как-нибудь избавиться от него.

Что касается "Pythonic" (и это происходит от выздоравливающего Pythonista), я могу только сказать, будьте уверены:

Всегда естьболее чем один очевидный способ сделать это в Прологе.

Вам даже не нужно быть голландцем.

...