Opiskelumateriaali - Logiikkaohjelmointi - Noppa
Transcription
Opiskelumateriaali - Logiikkaohjelmointi - Noppa
Ari Vesanen, Tietojenkäsittelytieteiden laitos, Oulun yliopisto 815338A Ohjelmointikielten periaatteet: Logiikkaohjelmointi Logiikkaohjelmointi Tässä osassa käsitellään toista deklaratiivisen ohjelmoinnin paradigmaa eli logiikkaohjelmointia. Pääasiallisena lähteenä on käytetty Sebestan ([Seb]) lukua 16. Maarit Harsun teoksen [Har] luvussa 14 perehdytään myös logiikkaohjelmointiin. Symboliseen logiikkaan perustuvaa ohjelmointia nimitetään logiikkaohjelmoinniksi ja tällaiseen ohjelmointiin soveltuvia kieliä logiikkaohjelmointikieliksi. Joissakin yhteyksissä nimitys deklaratiivinen kieli rajataan koskemaan pelkästään logiikkaohjelmointikieliä. Logiikkaohjelmointikielen syntaksi ja semantiikka eroaa imperatiivisen ohjelmointikielen vastaavista vielä voimakkaammin kuin funktionaalisten kielten. Logiikkaohjelmoinnissa ohjelmoija ei määrittele ratkaisuun johtavia toimenpiteitä, vaan ratkaisuun johtavia ominaisuuksia eli väittämiä, joiden oikeellisuuden ohjelma pyrkii päättelemään vertailemalla niitä tunnettuihin tosiasioihin. Tulos true merkitsee, että väittämä on oikea, mutta false merkitsee yleensä vain, että väittämää ei pystytty todistamaan oikeaksi. Ihannetapauksessa ohjelmoijan ei tarvitse keskittyä ratkaisuun johtavien toimenpiteiden ohjelmoimiseen vaan ratkaisun löytämisen logiikkaan. 1. Symbolisesta logiikasta Koska logiikkaohjelmointi perustuu vahvasti symbolisen logiikan käyttöön, tarkastellaan hieman sen ominaisuuksia. Diskreettien rakenteiden kurssissa käsitellään myös propositio- ja predikaattilogiikkaa (ks. [Kor], Luku 3). Propositio on looginen väittämä, jolla on totuusarvo. Symbolinen logiikka yksinkertaisimmillaan on propositio- eli lauselogiikkaa. Symbolisen logiikan avulla esitetään propositioiden välisiä suhteita ja johdetaan uusia väittämiä olemassa olevista. Propositiosymboleita (joilla usein on jokin tulkinta, esimerkiksi "On kylmä" tai "Sataa") yhdistellään käyttämällä loogisia konnektiiveja; nämä ovat Ari Vesanen, Tietojenkäsittelytieteiden laitos, Oulun yliopisto 815338A Ohjelmointikielten periaatteet: Logiikkaohjelmointi Nimi Symboli Esimerkki Semantiikka Negaatio ¬ ¬a ei a Konjunktio ∧ a∧b a ja b Disjunktio ∨ a∨b a tai b Implikaatio → tai ← a→b a:sta seuraa b a←b b:stä seuraa a a↔b a ja b yhtäpitävät Ekvivalenssi ↔ Propositiologiikassa negaatiolla on korkein preferenssi, minkä jälkeen tulevat konjunktio, disjunktio ja ekvivalenssi, jotka ovat preferenssiltään korkeammalla kuin implikaatio. Päättely-operaattoreiden = > ja < = > avulla voidaan muodostaa päättelyketjuja, joiden avulla saadaan uusia lauseita esimerkiksi seuraavasti: On kylmä → Palelee On kylmä ______________________________________ => Palelee Logiikkaohjelmoinnissa tarvittava symbolinen logiikka on predikaattilogiikkaa, jota kuvataan hieman seuraavaksi. Itse asiassa logiikkaohjelmoinnin käyttämä logiikka on jossakin propositio- ja predikaattilogiikan välimaastossa. Propositiologiikka ei sisällä muuttujia, joten se on liian yksinkertaista, predikaattilogiikka taas on ratkeamaton, ts. ei ole tehokasta algoritmia, jonka avulla voitaisiin päätellä onko jokin predikaatti tosi. Predikaattilogiikan avulla voidaan muodostaa ilmauksia, jotka koskevat propositiojoukkoja. Tätä varten loogisten lauseiden esittämisessä sallitaan lisäksi muuttujat, jotka esiintyvät aina kvanttoreiden ∀ (universaalikvanttori) ja ∃ Ari Vesanen, Tietojenkäsittelytieteiden laitos, Oulun yliopisto 815338A Ohjelmointikielten periaatteet: Logiikkaohjelmointi (eksistenssikvanttori) yhteydessä. Ensin mainittu tarkoittaa, että jokin ominaisuus pätee kaikilla arvoilla ja toinen, että on olemassa jokin arvo, jolle ominaisuus pätee, ts. ∀ Y:P ∃ Z:Q Kaikilla arvoilla Y P on tosi On olemassa sellainen Z että Q on tosi Presedenssijärjestyksessä kvanttorit ovat samalla tasolla kuin negaatio. Propositio on suljettu lause ja predikaatti on avoin lause, joka saadaan parametrisoimalla propositio. Predikaatista saadaan propositio korvaamalla parametrit eli muuttujat joillakin vakioilla. Predikaattilogiikan perusosat ovat: Vakiot, jotka edustavat tunnettuja alkioita. Vakioita merkitään yleensä pienillä kirjaimilla alkavilla tunnisteilla; lisäksi kokonaisluvut ovat vakioita. Muuttujat, jotka edustavat tuntemattomia alkioita. Niitä merkitään yleensä isoilla kirjaimilla alkavilla tunnisteilla. Funktiosymbolit eli funktorit (nimeävät funktioita). Predikaattisymbolit eli predikaatit, jotka määrittelevät alkioiden väliset relaatiot. Esimerkiksi ">": p(X,Y)= X > Y. Termit ovat lausekkeita jotka koostuvat vakioista, muuttujista ja funktoreista. Esimerkiksi f(X) + Y + 10. Atomikaava koostuu predikaatista, jonka argumenttina voi olla termi. Esimerkiksi f(Z)-X < 0. Kaava saadaan yhdistelemällä atomikaavoja loogisilla konnektiiveilla ja kvanttoreillla. Esimerkiksi ∃ Y ∀ X: (f(X) < 1) ∧ (Y > 0) Loogisella päättelyllä tarkoitetaan johtopäätösten muodostamista premisseistä (tunnetuista lauseista) loogisten päättelysääntöjen nojalla. Formaalisti oikea päättely tapahtuu siten, että kaavojen tai lauseiden semantiikka esitetään formaalisti ja noudatetaan korrektia semantiikkaa kussakin päättelysäännössä. Johtopäätökset vastaavat (yleensä) ihmisen käsitystä loogisista seurauksista. Ari Vesanen, Tietojenkäsittelytieteiden laitos, Oulun yliopisto 815338A Ohjelmointikielten periaatteet: Logiikkaohjelmointi Yksinkertaisimmat lauseet, joita käytetään logiikkaohjelmoinnissa, ovat atomisia propositioita, nämä koostuvat yhdistetyistä termeistä, jotka kirjoitetaan funktiokutsumaisessa muodossa. Yhdistetty termi muodostuu kahdesta osasta; funktorista ja järjestetystä parametrien listasta, esimerkiksi lammas(dolly) syö(dolly,ruoho) ovat yhdistettyjä termejä. Tässä esitetään ainoastaan, että relaatio lammas sisältää alkion {dolly} ja että relaatio syö sisältää järjestetyn kaksikon {dolly,ruoho}. Lauseiden semantiikka on deklaratiivista, ts. se on välittömästi nähtävissä lauseesta itsestään. Mitään tulkintaa lauseisiin ei kuitenkaan sinänsä sisälly. Esimerkiksi jälkimmäinen termi voi tarkoittaa, että dolly syö ruohoa, ruoho syö dollyä tai lause voi tarkoittaa jotakin aivan muuta. Ylläesitetyt lauseet koostuvat vakioista, mutta propositioissa voi myös esiintyä muuttujia. Atomisten propositioiden ja konnektiivien avulla voidaan muodostaa koottuja propositioita, esimerkiksi lammas(dolly) → nisäkäs(dolly) syö(dolly,X) ∧ liha(X) Jotta logiikkaohjelmointi olisi lainkaan hyödyllistä, siinä täytyy olla jonkinlaisia mekanismeja, joiden avulla johdetaan uusia sääntöjä. Sääntö voidaan johtaa annetuista tosista lauseista soveltamalla niihin äärellistä määrää peräkkäisiä päättelyjä. Logiikkaohjelmoinnissa päättelymekanismit perustuvat modus ponens- sääntöön ja universaalikvanttorin eliminointiin. Modus ponens: Lause A ∧ (A → B) voidaan korvata termillä B Universaalikvanttorin eliminoimissääntö: Lause ∀ X:A(X) voidaan korvata lauseella, jossa kaikki muuttujan X vapaat esiintymät on korvattu jollakin termillä. Ari Vesanen, Tietojenkäsittelytieteiden laitos, Oulun yliopisto 815338A Ohjelmointikielten periaatteet: Logiikkaohjelmointi Koneellisessa loogisessa päättelyssä suureksi ongelmaksi muodostuu keskenään ekvivalenttien lauseiden joukko, joka on kooltaan valtava. Siksi olisi toivottavaa määritellä jokin standardimuoto, jonka avulla propositiot voitaisiin esittää. Eräs tällainen on klausuuli. Klausuulin muoto on B1 ∨ B2 ∨ ...∨ BN ← A1 ∧ A2 ... ∧ AM Missä A:t ja B:t ovat termejä. Klausuulin semantiikka: Jos kaikki A:t ovat tosia, ainakin yksi B on tosi. Oikeaa puolta kutsutaan edellytykseksi (antecedent) ja vasenta puolta seuraukseksi (consequent). Vasen puoli toteutuu, kunhan vain oikea puoli voidaan osoittaa todeksi. Voidaan osoittaa, että kaikki predikaattilogiikan propositiot on algoritmisesti mahdollista muuttaa klausuuleiksi. Logiikkaohjelmoinnissa käytetään yleisesti erikoistapausta B ← A1 ∧ A2 ... ∧ AM jota kutsutaan Hornin klausuuliksi. Esimerkiksi syö(dolly,timotei) ← syö(dolly,ruoho)∧ ruoho(timotei) Mikäli Hornin klausuuli käsittää ainoastaan seurauksen (oikea puoli on tyhjä), sen vasen puoli on varauksetta tosi. Joskus tällaisia klausuuleja sanotaan myös faktoiksi. Alan Robinson kehitti vuonna 1965 ns. resoluutioperiaatteen tutkiessaan mahdollisuuksia automatisoida lauseiden todistusmekanismeja. Resoluutio on päättelymekanismi, jonka avulla annetuista propositioista johdetaan uusia propositioita. Resoluutioaskeleen periaate on hyvin yksinkertainen ja se perustuu modus ponens-eliminointisääntöön. Oletetaan esimerkiksi, että seuraavat säännöt ovat voimassa: P ← Q (1) R ← P (2) Tästä saadaan johdettua sääntö Ari Vesanen, Tietojenkäsittelytieteiden laitos, Oulun yliopisto 815338A Ohjelmointikielten periaatteet: Logiikkaohjelmointi R ← Q (3) Ensimmäisistä klausuuleista voidaan päätellä eräänlainen supistamismekanismi: kirjoitetaan P ∧ R ← Q ∧ P Ja "supistetaan" P pois, jolloin jäljelle jää klausuuli (3). Logiikkaohjelmoinnissa resoluutiomekanismissa joudutaan vielä huomioimaan muuttujat ja käyttämään lisäksi universaalikvanttorin eliminointisääntöä. Resoluutio yleistyy myös Hornin klausuuleille, joissa oikealla puolella on useampi termi. Resoluutiomekanismin käyttö logiikkaohjelmassa toimii seuraavasti: Kun halutaan todistaa jokin väite, se esitetään Hornin klausuulin oikeana puolena. Klausuuli yhdistetään tunnettuihin sääntöihin ja mikäli onnistutaan resoluution avulla saavuttamaan tyhjä klausuuli, on väite tosi. Väitettä voidaan myös nimittää kyselyksi (query). Esimerkki. Oletetaan säännöt (1) (2) (3) (4) jalat(x,2) ← nisäkäs(x) ∧ kädet(x,2) jalat(x,4) ← nisäkäs(x) ∧ kädet(x,0) nisäkäs(lammas) ← kädet(lammas,0) ← Halutaan todistaa väite jalat(lammas,4) Aluksi kirjoitetaan väite Hornin klausuulin oikeana puolena ← jalat(lammas,4) Yhdistetään tämä sääntöön (2), jolloin saadaan Ari Vesanen, Tietojenkäsittelytieteiden laitos, Oulun yliopisto 815338A Ohjelmointikielten periaatteet: Logiikkaohjelmointi jalat(x,4) ← nisäkäs(x) ∧ kädet(x,0) ∧ jalat(lammas,4) Korvataan x vakiolla lammas: jalat(lammas,4) ← nisäkäs(lammas) ∧ kädet(lammas,0) ∧ jalat(lammas,4) Resoluutiolla saadaan supistettua jalat(lammas,4) pois, joten tullaan lausekkeeseen ← nisäkäs(lammas) ∧ kädet(lammas,0) Yhdistetään tämä sääntöön (3): nisäkäs(lammas) ← nisäkäs(lammas) ∧ kädet(lammas,0) Resoluutiolla saadaan supistettua nisäkäs(lammas) pois ja lauseke saadaan muotoon ← kädet(lammas,0) Yhdistetään lopuksi tämä neljänteen sääntöön ja käytetään taas resoluutiota supistamaan kädet(lammas,0) pois: kädet(lammas,0) ← kädet(lammas,0) ← Päästiin siis tyhjään klausuuliin, joten väite on tosi. Ari Vesanen, Tietojenkäsittelytieteiden laitos, Oulun yliopisto 815338A Ohjelmointikielten periaatteet: Logiikkaohjelmointi 2. Prolog Tarkastellaan yleisimmän logiikkaohjelmointikielen Prologin ominaisuuksia. Prologin perusrakenteen suunnittelivat Colmerauer, Roussel sekä Kowalski, ja ensimmäinen Prolog-tulkki implementoitiin Marseillessa vuonna 1972. Kielestä on syntynyt monia murteita, joilla voi olla hyvinkin erilaiset syntaksit. Edinburghin yliopistossa luotu versio on kuitenkin saavuttanut jonkinlaisen standardin aseman. Kielelle on laadittu vuonna 1995 ISO-standardi, joka pohjautuu Edinburghin versioon. Prolog ei ole puhtaasti logiikkaohjelmointikieli, vaan sisältää piirteitä myös imperatiivisista ohjelmointikielistä. Prologin ominaisuuksia kuvataan tässä lähinnä Loudenin ([Lou], kappale 11) ja Sebestan ([Seb], kappaleet 16.5 – 16.7) mukaisesti. Prologissa käytetään samankaltaista notaatiota Hornin klausuuleille kuin yllä on esitetty, mutta nuolimerkintä ← on korvattu merkinnällä :- ja and -merkintä pilkulla, ts. Prologissa kirjoitettaisiin esi_isa(X,Y) :- vanhempi(X,Z), esi_isa(Z,Y). Prologissa erotetaan muuttujien ja vakioiden sekä predikaattien nimet siten, että muuttujien nimet alkavat isolla kirjaimella. Muuten alkukirjaimena käytetään pientä kirjainta. Prologin jokainen lause päättyy pisteeseen. Prologissa peruslauseista muodostuu oletetun tiedon tietokanta, jota hyväksi käyttäen voidaan johtaa uutta tietoa. Prologissa käytetään kahdentyyppisiä peruslauseita: Lauseet, jotka vastaavat Hornin klausuulien vasenta puolta ja lauseet jotka vastaavat varsinaisia Hornin klausuuleja. Ensin mainitut katsotaan faktoiksi, ts. loogisesti ne tulkitaan tosiksi lauseiksi. Toisen tyypin peruslauseita sanotaan myös säännöiksi. Prologissa väitteitä, joita halutaan todistaa, kutsutaan kyselyiksi (query) tai maalilauseiksi (goal) ja nämä esitetään Prolog -tulkille samassa muodossa kuin faktatkin. Oletetaan, että tietokantaan on syötetty lauseet esi_isa(X,Y) :- vanhempi(X,Z), esi_isa(Z,Y). esi_isa(X,X). vanhempi(nooa,haam). Ari Vesanen, Tietojenkäsittelytieteiden laitos, Oulun yliopisto 815338A Ohjelmointikielten periaatteet: Logiikkaohjelmointi Tällöin kysely esi_isa(nooa,haam) tuottaa tuloksen yes (tai true) ja kysely esi_isa(haam,nooa) tuloksen no (tai false). Samoin voidaan tehdä kysely esi_isa(X,haam) jolloin vastauksena saadaan X = nooa ->; (haetaan lisää) X = haam Prolog sisältää määrittelyt aritmeettisille operaatiolle ja niiden evaluoinnille. Prologille on kuitenkin kerrottava, milloin aritmeettista lauseketta tarkastellaan lausekkeena ja milloin se on evaluoitava. Esimerkiksi kirjoittamalla write(5+6). saa vastaukseksi 5+6. Mikäli haluaa Prologin evaluoivan summan, on kirjoitettava esimerkiksi X is 5+6, write(X). jolloin saa vastaukseksi X=11. Tästä aiheutuu mm. se että aritmeettisten lausekkeiden vertailu tuottaa tuloksen "no" mikäli lausekkeet ovat erilaiset siitä huolimatta, että niiden arvot olisivat samat. Siten 3+5 = 5+3 antaa tuloksen no. Jos halutaan vertailla lausekkeita niiden arvon perusteella, voidaan kirjoittaa predikaatti Ari Vesanen, Tietojenkäsittelytieteiden laitos, Oulun yliopisto 815338A Ohjelmointikielten periaatteet: Logiikkaohjelmointi sama_arvo(Termi1,Termi2) :- X is Termi1, Y is Termi2, X=Y. Tällöin syöttämällä sama_arvo(3+5,5+3) saadaan tulokseksi yes. Instantiointi tarkoittaa tyypin ja arvon liittämistä muuttujaan. Liittämisellä (unification) tarkoitetaan Prologissa prosessia, jolla kaksi muuttujaa instantioidaan sillä tavoin, että muuttujat täsmäävät resoluutiossa. Näin ollen liittäminen tarkoittaa jossakin mielessä kahden termin tekemistä samoiksi. Liittäminen ilmaistaan yhtäsuuruudella, esimerkiksi a = a -> yes (liittäminen onnistui) a = b -> no (eri vakioiden liittäminen ei onnistu) a = X -> X = a (muuttuja, jota ei ole instantioitu, liittyy mihin tahansa ja instantioituu tällä) f(a,Z) = f(Y,b) -> Z = b -> Y = a (liittäminen onnistuu kun Z=b ja Y = a) f(X) = g(X) -> no (kahden eri funktion liittäminen ei onnistu) Tarkastellaan seuraavaksi resoluution mekanismia Prologissa, ts. minkälaista hakustrategiaa käytetään johdettaessa tulosta. Resoluutiota sovelletaan täysin lineaarisesti siten, että maaleja korvataan vasemmalta oikealle ja tietokannan klausuuleja käydään läpi ylhäältä alaspäin. Alimaalit tarkastellaan välittömästi, kun ne Ari Vesanen, Tietojenkäsittelytieteiden laitos, Oulun yliopisto 815338A Ohjelmointikielten periaatteet: Logiikkaohjelmointi on määrätty. Tällaista strategiaa sanotaan syvyyssuntaiseksi (depth-first). Palataan aiempaan esimerkkiin esi_isa(X,Y) :- vanhempi(X,Z), esi_isa(Z,Y). esi_isa(X,X). vanhempi(nooa,haam). Olkoon annettu maali esi_isa(X,haam). Tällöin alimaalit muodostavat seuraavan hakupuun: Prolog palauttaa ensimmäisen vastaantulevan ratkaisun ja mikäli ratkaisuja halutaan lisää, puussa peräydytään (backtrack), kunnes löydetään uusia haaroja joita voidaan kulkea. Tämän kaltainen hakustrategia on tehokas, mutta kärsii samasta ongelmasta Ari Vesanen, Tietojenkäsittelytieteiden laitos, Oulun yliopisto 815338A Ohjelmointikielten periaatteet: Logiikkaohjelmointi kuin rekursiivisesti laskeutuva jäsentäjä: säännöissä ei saa olla vasemmanpuoleista rekursiota. Jos ensimmäinen sääntö olisi kirjoitettu esi_isa(X,Y) :- esi_isa(Z,Y), vanhempi(X,Z). Prolog joutuisi ikuiseen silmukkaan maalin johdossa yrittäessään toteuttaa lauseen esi_isa(Z,Y) soveltamalla toistuvasti ensimmäistä lausetta. Prologin peräytymismekanismia voidaan käyttää silmukoiden ja toistuvien hakujen toteuttamiseen, kunhan vain jotenkin pakotetaan etsinnän jatkaminen, vaikka ratkaisu löytyykin. Tätä varten Prologissa on predikaatti fail. Lisäksi haku voidaan katkaista operaattorilla !, joten ikuiset hakuprosessit voidaan ehkäistä. Tässä ei perehdytä näiden mekanismien yksityiskohtiin. Tarkastellaan vielä Prologin listarakenteita, jotka ovat Prolog-ohjelmoinnissa keskeisessä asemassa. Prologissa listaa merkitään hakasulkeilla, joiden sisällä ovat listan alkiot pilkulla erotettuna (esimerkiksi [a,b,c]), joten syntaksiltaan Prologin listat muistuttavat Haskellin listoja. Merkintä [] tarkoittaa tyhjää listaa. Prologissa ei ole listojen muodostamiseen ja purkamiseen erillisiä funktioita; sen sijaan kielessä käytetään merkintää [H|T] tarkoittamaan listaa, jonka pää on H ja häntä T. Prologin listojen muodostamisen perusoperaatioita on append, joka liittää listoja yhteen, esimerkiksi ?- Lista = [eka, toka, kolmas]. Lista = [eka, toka, kolmas]. ?- append($Lista,[nelj],Klista). Klista = [eka, toka, kolmas, nelj]. Ari Vesanen, Tietojenkäsittelytieteiden laitos, Oulun yliopisto 815338A Ohjelmointikielten periaatteet: Logiikkaohjelmointi Prologin append-operaatiota voidaan soveltaa myös päättelemään, minkä listojen yhdistäminen antaa tuloslistan: ?- append(X,Y,$Lista). X = [], Y = [eka, toka, kolmas]; X = [eka], Y = [toka, kolmas]; X = [eka, toka], Y = [kolmas]; X = [eka, toka, kolmas], Y = []; Esitetään vielä, miten listan kääntämisoperaatio voidaan toteuttaa Prologilla: kaanna([],[]). kaanna([H|T],K) :kaanna(T,K1),append(K1,[H],K). Tyhjän listan kääntäminen tuottaa tyhjän listan. Kun operaatiota sovelletaan epätyhjään listaan, käännetään ensin listan häntä, muodostetaan siitä lista K1 ja lisätään alkuun listan pää. Lopuksi käsitellään Prologin puutteita, jotka ainakin jossakin määrin koskevat yleisesti logiikkaohjelmointikieliä. Logiikkaohjelmointikielten piti alun perin muuttaa ohjelmointi spesifioinniksi ja vapauttaa ohjelmoija ratkaisun ohjelmoinnin yksityiskohdista. Tähän on pystytty vain osittain ja logiikkakielten päättelyissään käyttämät algoritmit ovat tuoneet omia ongelmia näillä kielillä ohjelmointiin. Esimerkiksi Prologin liittämisalgoritmi on itse asiassa epäkorrekti, tietyt määrittelyt johtavat sen ikuisiin silmukoihin (ks. [Lou], 11.5.1.). Prologissa on käytetty yksinkertaista ja tehokasta algoritmia, joka ei toimi oikein kaikissa erikoistapauksissa; tehokkaat ja korrektit algoritmit ovat huomattavasti monimutkaisempia. Looginen negaatio muodostuu ongelmalliseksi käsitteeksi logiikkakielissä niiden "suljetun maailman" oletuksen vuoksi. Logiikkakieli pitää väitettä vääränä, ellei sitä voida johtaa annetuista lauseista. Näin ollen väitteen negaatio on tosi, ellei väitettä Ari Vesanen, Tietojenkäsittelytieteiden laitos, Oulun yliopisto 815338A Ohjelmointikielten periaatteet: Logiikkaohjelmointi voida johtaa. Siten negaatio tarkoittaa pikemminkin epäonnistumista kuin loogista epätotuutta ja voi johtaa omalaatuisiin tuloksiin. Tietyssä mielessä myös logiikkaohjelmoinnin perimmäinen idea ratkaisun spesifioinnista sen tarkkojen yksityiskohtien ohjelmoimisen sijaan on ongelmallinen. Esimerkiksi lajitteluohjelman kirjoittaminen luonnollisimmalla tavalla johtaa listan kaikkien mahdollisten permutaatioiden generoimiseen, kunnes tavataan sellainen permutaatio, että lista on järjestyksessä. Tämä on luonnollisesti äärettömän tehoton tapa lajitella eikä sovellu käytännön ohjelmiin. Näin ollen ohjelmoijan on kuitenkin ohjelmoitava jokin konkreettinen lajittelualgoritmi ja logiikkaohjelmointi lähenee perinteisempiä ohjelmointimenetelmiä. (Prologilla voidaan kyllä esimerkiksi Quicksort algoritmi kirjoittaa varsin näppärästi). Logiikkakielten pääasialliset sovelluskohteet liittyvät tekoälyyn tavalla tai toisella, kielissä on sovellettu mm. luonnollisen kielen käsittelyyn ja asiantuntijajärjestelmien toteuttamiseen. Tekoälysovellusten ulkopuolella logiikkaohjelmointikieliä on käytetty toistaiseksi varsin vähän, mutta relaatiotietokantojen käsittelyyn niitä on ainakin sovellettu. Lähteet [Har] Harsu, Maarit. Ohjelmointikielet, Periaatteet, käsitteet, valintaperusteet, Talentum 2005. [Kor] Kortelainen, Juha. Diskreetit rakenteet 811120P, Luentomoniste. (https://noppa.oulu.fi/noppa/kurssi/811120p/materiaali/811120P_luennot_2.pdf). [Lou] Louden, Kenneth C. Programming Languages, Principles and Practice, PWS-KENT 1993. [Seb] Sebesta, Robert W. Concepts of Programming Languages 10th edition, Pearson 2013.