Конда, Конди, Конде, Проводник

Я читаю Разумный интриган.

У меня есть некоторая интуиция о том, как conde работает.

Тем не менее, я не могу найти формальное определение того, что conde/conda/condu/condi делать.

Я знаю о https://www.cs.indiana.edu/~webyrd/ но, похоже, есть примеры, а не определения.

Есть ли формальное определение conde, conda, condi, condu где-то?

3 ответа

Решение

С точки зрения Пролога, condA "мягкий крой", *->, а также condU это "совершенный выбор" - комбинация once и мягкий срез, так что (once(A) *-> B ; false) выражает разрез в (A, !, B):

A       *-> B ; C    %% soft cut, condA
once(A) *-> B ; C    %% committed choice, condU

В condA, если цель A успешно, все решения передаются в первом предложении B и нет альтернативных положений C пробуются. once/1 позволяет своей цели аргумента достичь успеха только один раз (сохраняет только одно решение, если оно есть).

condE это простая дизъюнкция, и condI это дизъюнкция, которая чередуется между решениями ее составляющих.


Вот попытка правдиво перевести код книги, без логических переменных и унификации, в 18 строк языка Haskell (где сопоставление - это применение функции карри, и : значит минусы). Посмотрите, проясняет ли это вещи:

  • Последовательная комбинация потоков (" mplus из книги):
    (1)   []     ++: ys = ys
    (2)   (x:xs) ++: ys = x:(xs ++: ys)
  • Комбинация переменного потока (" mplusI "):
    (3)   []     ++/ ys = ys
    (4)   (x:xs) ++/ ys = x:(ys ++/ xs)
  • Последовательная подача (" bind "):
    (5)   []     >>: g = []
    (6)   (x:xs) >>: g = g x ++: (xs >>: g)
  • Переменный корм (" bindI "):
    (7)   []     >>/ g = []
    (8)   (x:xs) >>/ g = g x ++/ (xs >>/ g)
  • " OR "комбинация целей (" condE "):
    (9)   (f ||: g) x = f x ++: g x
  • "Переменный OR "комбинация целей (" condI "):
    (10)  (f ||/ g) x = f x ++/ g x
  • " AND "комбинация целей (" all "):
    (11)  (f &&: g) x = f x >>: g
  • "Переменный AND "комбинация целей (" allI из книги):
    (12)  (f &&/ g) x = f x >>/ g
  • Особые цели
    (13)  true  x = [x]  -- a sigleton list with the same solution repackaged
    (14)  false x = []   -- an empty list, meaning the solution is rejected

Цели создают потоки (возможно, пустые) (возможно, обновленных) решений, учитывая (возможно, частичное) решение проблемы.

Переписать правила для all являются:

(all)    = true
(all g1) = g1
(all g1 g2 g3 ...)  = (\x -> g1 x >>: (all g2 g3 ...)) 
                    === g1 &&: (g2 &&: (g3 &&: ... ))
(allI g1 g2 g3 ...) = (\x -> g1 x >>/ (allI g2 g3 ...)) 
                    === g1 &&/ (g2 &&/ (g3 &&/ ... ))

Переписать правила для condX являются:

(condX) = false
(condX (else g1 g2 ...)) = (all g1 g2 ...) === g1 &&: (g2 &&: (...))
(condX (g1 g2 ...))      = (all g1 g2 ...) === g1 &&: (g2 &&: (...))
(condX (g1 g2 ...) (h1 h2 ...) ...) =
     (ifX g1 (all g2 ...) (ifX h1 (all h2 ...) (...) ))

Прибыть в финал condE а также condI перевод, нет необходимости реализовывать книгу ifE а также ifI, поскольку они в дальнейшем сводятся к простым комбинациям операторов, причем все операторы считаются правоассоциативными:

(condE (g1 g2 ...) (h1 h2 ...) ...) =
     (g1 &&: g2 &&: ... ) ||: (h1 &&: h2 &&: ...) ||: ...
(condI (g1 g2 ...) (h1 h2 ...) ...) =
     (g1 &&: g2 &&: ... ) ||/ (h1 &&: h2 &&: ...) ||/ ...

Таким образом, в Haskell не требуется никакого специального "синтаксиса", достаточно простых операторов. Любая комбинация может быть использована с &&/ вместо &&: если нужно. Но ОТОХ condI также может быть реализован как функция для принятия набора (список, дерево и т. д.) целей, которые должны быть выполнены, который будет использовать некоторую умную стратегию, чтобы выбрать из них наиболее вероятную или наиболее необходимую и т. д., а не просто двоичное чередование, как в ||/ оператор (или ifI книги).

Далее книга condA может моделироваться двумя новыми операторами, ~~> а также ||~, работать вместе. Мы можем использовать их естественным путем, как, например,

g1 ~~> g2 &&: ... ||~ h1 ~~> h2 &&: ... ||~ ... ||~ gelse

который может быть интуитивно понят как " IF g1 THEN g2 AND ... OR-ELSE IF h1 THEN ... OR-ELSE gelse ".

  • " IF-THEN Комбинация "цель"- это создание цели "try", которая должна вызываться с целью продолжения отказа:
    (15)  (g ~~> h) f x = case g x of [] -> f x ; ys -> ys >>: h
  • " OR-ELSE Комбинация цели из цели "try" и простой цели просто называет свою цель "try" со второй целью "по ошибке", так что это всего лишь вспомогательный синтаксис для автоматической группировки операндов:
    (16)  (g ||~ f) x = g f x

Если ||~ " OR-ELSE "Оператору дают меньшую силу связи, чем ~~> " IF-THEN "Оператор и сделал право-ассоциативный тоже, и ~~> оператор имеет еще меньшую силу связи, чем &&: и тому подобное, разумная группировка в вышеприведенном примере автоматически создается как

(g1 ~~> (g2 &&: ...)) ||~ ( (h1 ~~> (h2 &&: ...)) ||~ (... ||~ gelse)...)

Последний гол в ||~ Таким образом, цепь должна быть простой целью. На самом деле это не ограничение, так как последний пункт condA форма в любом случае эквивалентна простой AND "-комбинация своих целей (или просто false можно использовать так же хорошо).

Это все. У нас может быть даже больше типов целей-попыток, представленных различными видами IF операторы, если мы хотим:

  • использовать альтернативный канал в успешном предложении (для моделирования того, что можно было бы назвать condAI если таковой был в книге)
    (17)  (g ~~>/ h) f x = case g x of [] -> f x ; ys -> ys >>/ h
  • использовать успешный поток решений только один раз для создания эффекта обрезки, для моделирования condU:
    (18)  (g ~~>! h) f x = case g x of [] -> f x ; (y:_) -> h y

Так что, наконец, переписать правила для condA а также condU из книги просто:

(condA (g1 g2 ...) (h1 h2 ...) ...) = 
      g1 ~~> g2 &&: ... ||~ h1 ~~> h2 &&: ... ||~ ... 

(condU (g1 g2 ...) (h1 h2 ...) ...) = 
      g1 ~~>! g2 &&: ... ||~ h1 ~~>! h2 &&: ... ||~ ... 

Разумный Schemer покрывает conda (мягкое сокращение) и wire (совершенный выбор). Вы также найдете объяснения их поведения в превосходной диссертации Уильяма Берда о мини-Канрене. Вы отметили это сообщение как о core.logic. Чтобы быть ясным, core.logic основан на более новой версии miniKanren, чем та, что представлена ​​в The Reasoned Schemer. miniKanren всегда чередует дизъюнктивные цели - condi и чередующихся вариантов больше не существует. conde теперь condi.

Например, используя core.logic:

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

user>  (run* [w q]
                (conde [u#]
                       [(or* [(== w 1) (== w 2)])
                        (== q :first)]
                       [(== q :second)]))
([_0 :second] [1 :first] [2 :first])

Conda и Condu: оба остановятся после первой успешной группы (сверху вниз)

Конда возвращает все результаты только из первой успешной группы.

user> (run* [w q]
                (conda [u#]
                       [(or* [(== w 1) (== w 2)])
                        (== q :first)]
                       [(== q :second)]))
([1 :first] [2 :first])

Проводник возвращает только один результат только из первой успешной группы.

user> (run* [w q]
                (condu [u#]
                       [(or* [(== w 1) (== w 2)])
                        (== q :first)]
                       [(== q :second)]))
([1 :first])

Хотя понятия не имею, что делает condi.

В соответствии с основным стандартом ISO Prolog контрольные структуры, такие как (,)/2, (;)/2 и (->)/2, вырезаны прозрачными. (*->)/2 не встречается в основном стандарте ISO Prolog, но обычно системы Prolog реализуют его также прозрачно.

Это означает, что нельзя переводить:

once(A) *-> B;C

В A, !, B; C, Поскольку последние могут быть встроены в другие управляющие структуры, и если между ними существуют разногласия, эти точки выбора также будут исключены. Что, с другой стороны, кажется разумным, чтобы рассматривать это как A -> B; C,

известный просто как основной стандарт ISO Prolog if-then-else. Определенное таким образом поведение разреза, например, полезно для выхода из повторяющихся циклов без исключения. Обычный шаблон программирования сложнее архивировать с помощью if-then-else.

Другие вопросы по тегам