Quali sono le principali differenze tecniche tra Prolog e miniKanren, rispetto alla programmazione logica? [chiuso]


124

Quando voglio leggere sulla programmazione logica, inciampo sempre in due modi "principali" per farlo al giorno d'oggi:

  • miniKanren , una minilingua introdotta in The Reasoned Schemer e popolare al momento grazie a core.logic .
  • Prolog , il primo "grande" linguaggio di programmazione logica.

Quello che mi interessa ora: quali sono le principali differenze tecniche tra i due? Sono molto simili nell'approccio e nell'implementazione o adottano approcci completamente diversi alla programmazione logica? Da quali rami della matematica provengono e quali sono i fondamenti teorici?


3
Triste vedere questa domanda chiusa. Come dimostrato dalla risposta molto convincente e dal gran numero di voti positivi, questa è una domanda perfettamente utile. Ho votato per riaprire ...
nealmcb

Le domande di @nealmcb che una volta erano in argomento con molti voti positivi potrebbero non esserlo più, la quantità di voti positivi non è ciò che lo definisce valido o meno.
Tiago Martins Peres 李大仁

Risposte:


281

Per prima cosa, permettimi di farti i complimenti per la tua bella icona pw0n1e.

Questa è una domanda difficile a cui rispondere, soprattutto perché ci sono così tante varianti sia di miniKanren che di Prolog. miniKanren e Prolog sono in realtà famiglie di linguaggi, il che rende difficile confrontare le loro caratteristiche o anche il modo in cui vengono utilizzate nella pratica. Per questo motivo, prendi con cautela tutto ciò che sto per dire: se dico che Prolog utilizza la ricerca approfondita, tieni presente che molte implementazioni di Prolog supportano altre strategie di ricerca e che le strategie di ricerca alternative possono anche essere codificate nel meta -livello interprete. Tuttavia, miniKanren e Prolog hanno filosofie di progettazione diverse e fanno diversi compromessi.

Il prologo è uno dei due linguaggi classici per la programmazione dell'intelligenza artificiale simbolica (l'altro linguaggio classico è Lisp). Prolog eccelle nell'implementazione di sistemi simbolici basati su regole in cui la conoscenza dichiarativa è codificata nella logica del primo ordine. Il linguaggio è ottimizzato per espressività ed efficienza per questi tipi di applicazioni, a volte a scapito della purezza logica. Ad esempio, per impostazione predefinita Prolog non utilizza il "controllo di verifica" nell'unificazione. Da un punto di vista matematico / logico, questa versione dell'unificazione non è corretta. Tuttavia, il controllo in corso è costoso e nella maggior parte dei casi la mancanza del controllo in corso non è un problema. Questa è una decisione di progettazione molto pragmatica, così come l'uso di Prolog della ricerca in profondità e l'uso del taglio (!) per controllare il backtracking. Sono sicuro che queste decisioni erano assolutamente necessarie quando si eseguiva l'hardware degli anni '70, e oggi sono molto utili quando si lavora su grandi problemi e quando si ha a che fare con spazi di ricerca enormi (spesso infiniti!).

Prolog supporta molte funzionalità "extra-logiche" o "non logiche", incluso il taglio asserte la retractproiezione di variabili per l'uso aritmeticois, e così via. Molte di queste caratteristiche rendono più facile esprimere un flusso di controllo complesso e manipolare il database globale dei fatti di Prolog. Una caratteristica molto interessante di Prolog è che il codice Prolog è esso stesso memorizzato nel database globale dei fatti e può essere interrogato in fase di esecuzione. Questo rende banale scrivere meta-interpreti che modificano il comportamento del codice Prolog sotto interpretazione. Ad esempio, è possibile codificare la ricerca in ampiezza in Prolog utilizzando un meta-interprete che modifica l'ordine di ricerca. Questa è una tecnica estremamente potente che non è molto conosciuta al di fuori del mondo Prolog. "The Art of Prolog" descrive questa tecnica in dettaglio.

Sono stati compiuti sforzi enormi per migliorare le implementazioni di Prolog, la maggior parte delle quali sono basate sulla Warren Abstract Machine (WAM). Il WAM utilizza un modello con effetti collaterali in cui i valori vengono assegnati in modo distruttivo alle variabili logiche, con questi effetti collaterali che vengono annullati durante il backtracking. Molte funzionalità possono essere aggiunte a Prolog estendendo le istruzioni del WAM. Uno svantaggio di questo approccio è che i documenti di implementazione di Prolog possono essere difficili da leggere senza una solida conoscenza del WAM. D'altra parte, l'implementatore di Prolog ha un modello comune per discutere i problemi di implementazione. Parallelamente a Prolog sono state svolte molte ricerche, culminate in Andorra Prolog negli anni '90. Almeno alcune di queste idee vivono in Ciao Prolog. (Ciao Prolog è pieno di idee interessanti, molte delle quali vanno ben oltre lo standard Prolog.)

Prolog ha una bellissima sintassi in stile "pattern-matching" basata sull'unificazione che si traduce in programmi molto succinti. I prologi amano la loro sintassi, proprio come i Lispers amano le loro espressioni s. Prolog dispone anche di un'ampia libreria di predicati standard. A causa di tutta l'ingegneria necessaria per rendere veloce il WAM, ci sono implementazioni Prolog molto capaci e mature. Di conseguenza, molti grandi sistemi basati sulla conoscenza sono stati scritti interamente in Prolog.

miniKanren è stato progettato come un linguaggio di programmazione logico minimale, con un'implementazione piccola, facilmente comprensibile e facilmente hackerabile. miniKanren era originariamente incorporato in Scheme ed è stato portato in dozzine di altre lingue ospitanti negli ultimi dieci anni. L'implementazione di miniKanren più popolare è "core.logic" in Clojure, che ora ha molte estensioni simili a Prolog e una serie di ottimizzazioni. Recentemente il nucleo dell'implementazione di miniKanren è stato ulteriormente semplificato, risultando in un minuscolo "micro kernel" chiamato "microKanren". miniKanren può quindi essere implementato su questo core microKanren. Il porting di microKanren o miniKanren in una nuova lingua host è diventato un esercizio standard per i programmatori che imparano miniKanren. Di conseguenza,

Le implementazioni standard di miniKanren e microKanren non contengono mutazione o altri effetti collaterali, con una sola eccezione: alcune versioni di miniKanren utilizzano l'uguaglianza dei puntatori per confrontare le variabili logiche. Lo considero un "effetto benefico", sebbene molte implementazioni evitino anche questo effetto passando un contatore attraverso l'implementazione. Inoltre, non esiste un database dei fatti globale. La filosofia di implementazione di miniKanren è ispirata dalla programmazione funzionale: la mutazione e gli effetti dovrebbero essere evitati e tutti i costrutti del linguaggio dovrebbero rispettare l'ambito lessicale. Se osservi attentamente l'implementazione potresti persino individuare un paio di monadi. L'implementazione della ricerca si basa sulla combinazione e la manipolazione di flussi pigri, ancora una volta senza utilizzare la mutazione. Queste scelte di implementazione portano a compromessi molto diversi rispetto a Prolog. In Prolog, la ricerca delle variabili è un tempo costante, ma il backtracking richiede l'annullamento degli effetti collaterali. In miniKanren la ricerca delle variabili è più costosa, ma il backtracking è "gratuito". In effetti, non c'è backtracking in miniKanren, a causa di come vengono gestiti i flussi.

Un aspetto interessante dell'implementazione di miniKanren è che il codice è intrinsecamente thread-safe e --- almeno in teoria --- banalmente parallelizzabile. Ovviamente, parallelizzare il codice senza renderlo più lento non è banale, dato che a ogni thread o processo deve essere dato abbastanza lavoro per compensare il sovraccarico della parallelizzazione. Tuttavia, questa è un'area dell'implementazione di miniKanren che spero riceverà più attenzione e sperimentazione.

miniKanren utilizza il controllo degli eventi per l'unificazione e utilizza una ricerca interleaving completa invece di una ricerca approfondita. La ricerca interleaving utilizza più memoria rispetto alla ricerca in profondità, ma può trovare risposte in alcuni casi in cui la ricerca in profondità diverge / continua per sempre. miniKanren fa sostenere alcuni operatori extra-logici --- conda, condue project, per esempio. condae condupuò essere utilizzato per simulare il taglio di Prolog e projectpuò essere utilizzato per ottenere il valore associato a una variabile logica.

La presenza di conda, condueproject--- e la capacità di modificare facilmente la strategia di ricerca --- consente ai programmatori di utilizzare miniKanren come linguaggio incorporato simile a Prolog. Ciò è particolarmente vero per gli utenti di "core.logic" di Clojure, che include molte estensioni simili a Prolog. Questo uso "pragmatico" di miniKanren sembra spiegare la maggior parte dell'uso di miniKanren nell'industria. I programmatori che desiderano aggiungere un sistema di ragionamento basato sulla conoscenza a un'applicazione esistente scritta in Clojure o Python o JavaScript non sono generalmente interessati a riscrivere l'intera applicazione in Prolog. Incorporare un piccolo linguaggio di programmazione logica in Clojure o Python è molto più attraente. Un'implementazione Prolog incorporata funzionerebbe altrettanto bene per questo scopo, presumibilmente.

Oltre all'uso di miniKanren come un pragmatico linguaggio di programmazione logica incorporata simile nello spirito a Prolog, miniKanren viene utilizzato per la ricerca nella programmazione "relazionale". Cioè, nella scrittura di programmi che si comportano come relazioni matematiche piuttosto che come funzioni matematiche. Ad esempio, in Scheme la appendfunzione può aggiungere due elenchi, restituendo un nuovo elenco: la chiamata alla funzione (append '(a b c) '(d e))restituisce l'elenco (a b c d e). Tuttavia, possiamo anche trattare appendcome una relazione a tre posti piuttosto che come una funzione a due argomenti. La chiamata (appendo '(a b c) '(d e) Z)associa quindi la variabile logica Zall'elenco (a b c d e). Ovviamente le cose diventano più interessanti quando posizioniamo le variabili logiche in altre posizioni. La chiamata si (appendo X '(d e) '(a b c d e))associa Xa (a b c), mentre la chiamata(appendo X Y '(a b c d e))associati Xe Ycon coppie di elenchi che, se aggiunti, sono uguali a (a b c d e). Ad esempio X= (a b)e Y= (c d e)sono una di queste coppie di valori. Possiamo anche scrivere (appendo X Y Z), che produrrà un numero infinito di triple di liste X, Ye Zin modo tale che aggiungendo Xalla Yproduce Z.

Questa versione relazionale di appendpuò essere facilmente espressa in Prolog, e in effetti è mostrata in molti tutorial di Prolog. In pratica, i programmi Prolog più complessi tendono a utilizzare almeno alcune caratteristiche extra logiche, come il taglio, che inibiscono la capacità di trattare il programma risultante come una relazione. Al contrario, miniKanren è esplicitamente progettato per supportare questo stile di programmazione relazionale. Più recenti versioni di miniKanren hanno il supporto per risolvere simbolica vincolo ( symbolo, numbero,absento, vincoli di disuguaglianza, programmazione logica nominale) per rendere più facile scrivere programmi non banali come relazioni. In pratica non uso mai nessuna delle caratteristiche extra logiche di miniKanren, e scrivo tutti i miei programmi miniKanren come relazioni. I programmi relazionali più interessanti sono gli interpreti relazionali per un sottoinsieme di Scheme. Questi interpreti hanno molte capacità interessanti, come la generazione di un milione di programmi Scheme che valutano l'elenco (I love you)o la generazione banale di quines (programmi che valutano a se stessi).

miniKanren fa una serie di compromessi per abilitare questo stile di programmazione relazionale, che sono molto diversi dai compromessi che Prolog fa. Nel corso del tempo miniKanren ha aggiunto ulteriori vincoli simbolici, diventando davvero un linguaggio di programmazione con logica vincolante orientato simbolicamente. In molti casi questi vincoli simbolici rendono pratico evitare l'uso di operatori extra logici come condue project. In altri casi, questi vincoli simbolici non sono sufficienti. Un supporto migliore per i vincoli simbolici è un'area attiva della ricerca miniKanren, insieme alla domanda più ampia di come scrivere programmi più grandi e complessi come relazioni.

In breve, sia miniKanren che Prolog hanno caratteristiche, implementazioni e usi interessanti e penso che valga la pena imparare le idee da entrambe le lingue. Ci sono anche altri linguaggi di programmazione logica molto interessanti, come Mercury, Curry e Gödel, ognuno dei quali ha il proprio approccio alla programmazione logica.

Concluderò con alcune risorse miniKanren:

Il sito web principale di miniKanren: http://minikanren.org/

Un'intervista che ho rilasciato sulla programmazione relazionale e miniKanren, incluso un confronto con Prolog: http://www.infoq.com/interviews/byrd-relational-programming-minikanren

Saluti,

--Volere


9
Scusami se sono sbalordito adesso. Ho appena iniziato i primi esperimenti mentali di logica e programmazione basata su vincoli e questa è la risposta che ottengo. :) In realtà, come hai detto anche nella tua risposta, avevo un forte sospetto che il calcolo logico fosse un candidato perfetto da implementare come Monade; si scopre che è più un MonadPlus e c'è davvero un documento e un'implementazione di riferimento del tuo collega Friedman! Quindi lo sto leggendo e ci sto giocando adesso, qualche idea al riguardo?
Profpatsch

4
Sospetto che troverai interessante anche il documento e il codice di microKanren : webyrd.net/scheme-2013/papers/HemannMuKanren2013.pdf e github.com/jasonhemann/microKanren
William E. Byrd

5
Inoltre, organizzo un corso settimanale di miniKanren su Google Hangouts, la domenica alle 15:00 ora orientale (GMT -5: 00). Ho sempre twittato il link dal mio account Twitter @webyrd, se vuoi unirti a noi. Gli hangout registrati in precedenza sono su: youtube.com/playlist?list=PLO4TbomOdn2cks2n5PvifialL8kQwt0aW
William E. Byrd

2
Penso che sia fondamentalmente la stessa monade di ricerca del documento del '05. Inoltre, vedi "Embedding Prolog in Haskell" di Seres e Spivey: spivey.oriel.ox.ac.uk/~mike/silvija/seres_haskell99.pdf
William E. Byrd

1
@ WilliamE.Byrd - Risposta fantastica! Supponendo che ce ne sia uno, qual è la migliore implementazione miniKanren che può essere incorporata in un programma C / C ++? Inoltre, miniKanren ha la natura generativa di Prolog? Cioè, la possibilità di lasciare una variabile in un'espressione non messa a terra e il motore principale genererà tutti i possibili valori per la variabile non messa a terra date le relazioni correnti dichiarate dal programma?
Robert Oschler

4

Risposta provvisoria:

AFAIK, "The Reasoned Schemer" ha introdotto la programmazione logica di base in una sintassi Scheme-y e uno stile di programmazione funzionale, aggiungendo in particolare gli obiettivi costanti "#u" (fail) e "#s" (suceeed) ai valori booleani "#t "e" #f ". Ha utilizzato lo stesso approccio alla programmazione logica di Prolog: Unification e backtracking search. Vedrò se avrò un po 'di tempo per recuperare quel libro dallo scaffale durante il fine settimana. Il ramo della matematica è una logica del primo ordine in forma ristretta, in questo caso clausole di Horn e la risoluzione unfication. Vedere: Logica computazionale: Memories of the Past and Challenges for the Future di John Alan Robinson e The early years of logic programming di Robert Kowalski per un avvio a freddo.


3
Cosa hanno a che fare queste due citazioni con Kanren o MiniKanren?
falso

2
Vedi l'ultima domanda: "Da quali rami della matematica provengono e quali sono i fondamenti teorici?"
Frank Shearar
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.