[tutor] Update assignment
This commit is contained in:
parent
39c3af4ba5
commit
ca687c0136
18 changed files with 438 additions and 14 deletions
|
@ -2,12 +2,13 @@
|
|||
|
||||
Er is een nijpend tekort aan Prolog-implementaties. Om dit probleem op te lossen, is het jouw taak om een eigen Prolog-interpreter *Ghent Prolog* te bouwen. Deze interpreter moet een subset van Prolog ondersteunen en in staat zijn om eenvoudige logische regels en queries uit te voeren alsook minstens één complexere Prolog constructie ondersteunen.
|
||||
|
||||
Je bent volledig vrij om de programmeertaal waarin je de Prolog-interpreter maakt zelf te kiezen. Let er echter op dat je code beoordeeld zal worden op leesbaarheid en dat je de implementatie moet kunnen uitleggen tijdens je verdediging. Gebruik van esoterische programmeertalen, zoals gesuggereerd tijdens het hoorcollege, wordt daarom ten zeerste afgeraden.
|
||||
Je bent volledig vrij om de programmeertaal waarin je de Prolog-interpreter maakt zelf te kiezen (Prolog zelf is niet toegestaan). Let er echter op dat je code beoordeeld zal worden op leesbaarheid en dat je de implementatie moet kunnen uitleggen tijdens je verdediging. Gebruik van esoterische programmeertalen, zoals gesuggereerd tijdens het hoorcollege, wordt daarom ten zeerste afgeraden.
|
||||
|
||||
In dit document geven we een overzicht van de basis functionaliteit van deze interpreter.
|
||||
Verder geven we de vereisten waaraan je project moet voldoen.
|
||||
|
||||
## Doel van de Opgave
|
||||
|
||||
Het doel van de opgave is om een basisimplementatie van een Prolog-interpreter maken, we testen hiermee dat je kennis hebt van de volgende Prolog concepten.
|
||||
|
||||
* Unificatie.
|
||||
|
@ -25,17 +26,17 @@ Om ervoor te zorgen dat we alle interpreters op dezelfde manier kunnen testen zu
|
|||
|
||||
Veronderstel dat de onderstaande code in een bestand `test.pl` staat.
|
||||
|
||||
```
|
||||
```pl
|
||||
:- initialization(main).
|
||||
|
||||
main :- write(10),
|
||||
nl,
|
||||
write(hello(world)).
|
||||
write(hello(world)).
|
||||
```
|
||||
|
||||
Dan zal je interpreter *gpl* moeten gestart kunnen worden op de command line als volgt:
|
||||
|
||||
```
|
||||
```bash
|
||||
gpl -s test.pl
|
||||
10
|
||||
hello(world)
|
||||
|
@ -43,15 +44,13 @@ hello(world)
|
|||
|
||||
In onze testen zullen we interpreter testen door *swipl* uit te voeren als volgt:
|
||||
|
||||
```
|
||||
```bash
|
||||
swipl -t halt -q -s test.pl
|
||||
10
|
||||
hello(world)
|
||||
```
|
||||
Onze test zal dan simpelweg bekijken of de uitvoer van *gpl* overeenkomt met deze van *swipl*.
|
||||
|
||||
|
||||
|
||||
## Functionaliteit
|
||||
|
||||
Hieronder volgt een lijst met de meest voor de hand liggende functionaliteiten die je moet ondersteunen, voor meer informatie kan je altijd de Prolog documentatie raadplegen. Twijfel je tijdens de implementatie of bepaalde functionaliteiten nodig zijn voor de basisimplementatie? Neem dan gerust contact met ons op.
|
||||
|
@ -60,7 +59,7 @@ Hieronder volgt een lijst met de meest voor de hand liggende functionaliteiten d
|
|||
|
||||
Je interpreter moet minimaal de volgende twee modi ondersteunen:
|
||||
|
||||
- [ ] een script mode (gpl -s)
|
||||
- [ ] een script mode (`gpl -s`)
|
||||
- [ ] een read-eval-print loop (`gpl --repl` of `gpl -r`)
|
||||
|
||||
|
||||
|
@ -68,9 +67,10 @@ Je interpreter moet minimaal de volgende twee modi ondersteunen:
|
|||
|
||||
Deze functionaliteit is bijzonder belangrijk gezien de automatische testen hiervan gebruik zullen maken. Het gebruik van `initalization` is om Goal op te roepen direct na het inladen van de file, SWIPL heeft ook ondersteuning voor saved states, dit moet je niet implementeren.
|
||||
|
||||
- [ ] write(+Term)
|
||||
- [ ] read(-Term)
|
||||
- [ ] :- initialization(:Goal)
|
||||
- [ ] `write(+Term)`
|
||||
- [ ] `nl/0`
|
||||
- [ ] `read(-Term)`
|
||||
- [ ] `:- initialization(:Goal)`
|
||||
|
||||
|
||||
**Control Constructs**
|
||||
|
@ -100,6 +100,7 @@ Deze functionaliteit is bijzonder belangrijk gezien de automatische testen hierv
|
|||
|
||||
**database operations**
|
||||
|
||||
- [ ] `dynamic/1`
|
||||
- [ ] `assert/1`
|
||||
- [ ] `asserta/1`
|
||||
- [ ] `assertz/1`
|
||||
|
@ -122,14 +123,12 @@ Een leuke uitbreiding voor je Prolog-interpreter is de ondersteuning van lijsten
|
|||
|
||||
Zorg voor een set van testen die je predicaten testen.
|
||||
|
||||
|
||||
### DCG support
|
||||
|
||||
Een interessante uitbreiding voor je Prolog-interpreter is de ondersteuning van Definite Clause Grammars (DCG), een ingebouwde manier om grammatica’s en parsers te definiëren in Prolog. DCG’s worden vaak gebruikt voor het verwerken van natuurlijke taal en het bouwen van parsers voor programmeertalen. Hint: Het boek legt uit hoe je DCG's syntax kan omzetten naar traditionele Prolog regels.
|
||||
|
||||
Voor meer info raadpleeg de Prolog documentatie [DCG](https://www.swi-prolog.org/pldoc/man?section=DCG).
|
||||
|
||||
|
||||
### Meta abstracties
|
||||
Een krachtige uitbreiding voor je Prolog-interpreter is de ondersteuning van meta-abstracties, waarmee Prolog-code zichzelf kan inspecteren. Meta-abstracties maken het mogelijk om programma’s te schrijven die andere Prolog-programma’s manipuleren, analyseren of zelfs uitbreiden. Implementeer hiervoor minstens de volgende predicaten:
|
||||
|
||||
|
@ -183,6 +182,21 @@ Voeg aan je verslag je code toe met lijnnummers zodat je in de uitleg van je ver
|
|||
Op het einde van het semester zal je ook jouw project mondeling moeten voorstellen.
|
||||
De dag van de verdedigingen zal later worden meegedeeld.
|
||||
|
||||
# Testen
|
||||
|
||||
Een deel van de automatische testen die we zullen gebruiken om je project te evalueren zijn beschikbaar in de map `examples/`.
|
||||
Bovendien kan je de basis testen (`examples/basics/`) ook runnen via de docker:
|
||||
|
||||
```bash
|
||||
docker pull tolauwae/lp-project-2024-2025:latest
|
||||
docker run --rm --mount type=bind,source={PROJECT REPO}/src,target=/staging/project tolauwae/lp-project-2024-2025:latest ./project/gpl
|
||||
```
|
||||
|
||||
Waarbij {PROJECT REPO} de locatie van je project repository is.
|
||||
|
||||
De docker image gebruikt de officiële SWI-Prolog image net als de automatische testen bij het verbeteren van je project.
|
||||
De image gebruikt swipl versie 9.2.9 (laatste stable versie).
|
||||
|
||||
# Indienen
|
||||
|
||||
Het indienen van het project gebeurd via **GitHub Classroom**.
|
||||
|
@ -198,7 +212,22 @@ Als hiermee iets fout loopt, contacteer ons dan zo snel mogelijk.
|
|||
> [!IMPORTANT]
|
||||
> De laatste commit op de branch `main` van je fork op de deadline geldt als je indiening.
|
||||
|
||||
## Vorm
|
||||
### GitHub Actions
|
||||
|
||||
GitHub actions gebruiken op de indien repo is niet toegestaan (disabled voor alle repos). Je kan echter een eigen private fork van je indien-repo maken en daar je code testen met GitHub Actions. Lokaal op je eigen machine werk je dan met twee remotes:
|
||||
|
||||
```bash
|
||||
git remote -v
|
||||
indien git@github.com:Logisch-Programmeren/project2425-tolauwae.git (fetch)
|
||||
indien git@github.com:Logisch-Programmeren/project2425-tolauwae.git (push)
|
||||
origin git@github.com:tolauwae/project2425-tolauwae.git (fetch)
|
||||
origin git@github.com:tolauwae/project2425-tolauwae.git (push)
|
||||
```
|
||||
|
||||
We maken wel een uitzondering voor self-hosted runners, als je dit hebt opgezet stuur ons dan een mailtje en dan laten we actions weer toe voor jouw repo.
|
||||
|
||||
## Vorm
|
||||
|
||||
Je project moet volgende structuur hebben:
|
||||
|
||||
- `src/` bevat alle broncode (inclusief `gpl`).
|
||||
|
|
50
FAQ.md
Normal file
50
FAQ.md
Normal file
|
@ -0,0 +1,50 @@
|
|||
# Frequently Asked Questions
|
||||
|
||||
1. Hoe moet ik aan het project beginnen?
|
||||
|
||||
> Belangrijk is het doel voor ogen te houden, en duidelijk te onthouden wat belangrijk is. De Prolog interpreter steunt op twee zaken: unificatie + backtracking.
|
||||
> Het implementeren van deze twee componenten is het belangrijkste deel van het project. Laat je interne representatie van termen hier ook vanaf hangen, en niet van je parser!
|
||||
|
||||
> Begin met deze twee zaken goed te snappen, en je zal zien dat deze mits goeie planning in verrassend weinig lijnen kunnen geschreven worden.
|
||||
|
||||
> Daarnaast is ook je parser een belangrijke component, maar parsers zijn overal te vinden en daarom bestaan er dus veel bibliotheken voor. Gebruiken deze bibliotheken en vindt niet het wiel opnieuw uit.
|
||||
|
||||
2. Mag ik GitHub actions gebruiken?
|
||||
|
||||
> Ja, maar de GitHub runners van de indien repo zijn enkel beschikbaar voor de assistenten. Je kan dus enkel GitHub actions gebruiken op een eigen private fork van de indien repo. Op de indien repo zelf kan je geen GitHub actions gebruiken, tenzij je een eigen runnen opzet (neem dan contact op met de assistent).
|
||||
|
||||
3. Mag ik libraries gebruiken?
|
||||
|
||||
> Ja! Algemene libraries mag je zeker gebruiken. Bibliotheken die delen van de prolog interpreter implementeren zijn uiteraard niet toegelaten. Als je twijfelt over een library, dan kan je steeds de assistent mailen voor toestemming.
|
||||
|
||||
4. Mag ik de interpreter in Prolog implementeren?
|
||||
|
||||
> Nee.
|
||||
|
||||
5. Moeten we haakjes ondersteunen voor disjunctie? Bijvoorbeeld: Vader = anakin , (father(Vader, leia) ; father(Vader, luke)).
|
||||
|
||||
> Nee.
|
||||
|
||||
6. Moeten we in de REPL ook choice points ondersteunen?
|
||||
|
||||
> Ja, je moet ook choice points ondersteunen op dezelfde manier als swipl, waarbij je gpl laat verder zoeken met `;`.
|
||||
|
||||
7. Moeten we ook `append` ondersteunen voor de lijst uitbreiding?
|
||||
|
||||
> Ja, de drie predicaten de we oplijsten in de opgave zijn boven de standaard operaties op lijsten: append en member.
|
||||
|
||||
8. Hoe moeten we unificatie implementeren?
|
||||
|
||||
> Als je nog moeite hebt met het unificatie algorithme, kijk dan zeker eerst opnieuw naar de slides en je lesnota's. In de oefeningenreeks van week 3 hebben we ook een [uitgebreide oefening](https://dodona.be/en/courses/4816/series/54910/activities/930425534/) gemaakt over het unificatie algorithme, waarbij we een occurs check toevoegden. Deze oefening gaf een implementatie van het unificatie algorithme voor twee termen in Prolog.
|
||||
>
|
||||
> Daarnaast kan je ook het boek "The Art of Prolog" raadplegen (beschikbaar als fysiek en ebook in de [universiteitsbibliotheek](https://lib.ugent.be/en/catalog?q=the+art+of+prolog)). In dit boek wordt het unificatie algorithme uitgebreid besproken in hoofdstuk 4.
|
||||
|
||||
9. Wordt ons project automatisch getest?
|
||||
|
||||
> Ja, in de opgave repo vind je enkele voorbeeld programma's uit de automatische testen onder de map `examples`.
|
||||
> Er is tevens een docker image ter beschikking met de exacte configuratie die wij zullen gebruiken om je project te testen.
|
||||
|
||||
10. Wordt de output enkel exact vergeleken met die van swipl?
|
||||
|
||||
> De automatische testen maken vooral gebruik van het `write(predicaat)`, waarbij we de output exact zullen vergelijken. Indien voor uitzonderlijke gevallen je output wel juist is, maar toch verschilt van swipl (door een verschil in het unificatiealgoritme) dan zullen wij daar rekening mee houden bij het verbeteren.
|
||||
|
30
examples/basics/arithmetics.pl
Normal file
30
examples/basics/arithmetics.pl
Normal file
|
@ -0,0 +1,30 @@
|
|||
name( character(Name, _, _, _), Name).
|
||||
class( character( _, Class, _, _), Class).
|
||||
level( character( _, _, Level, _), Level).
|
||||
hitpoints(character( _, _, _, HP), HP).
|
||||
|
||||
levelup(character(Name, Class, Level, HP), character(Name, Class, Next, HP)) :-
|
||||
succ(Level, Next).
|
||||
|
||||
aid(character(Name, Class, Level, HP), character(Name, Class, Level, T)) :-
|
||||
T is HP+5.
|
||||
|
||||
hit(character(Name, Class, Level, HP), character(Name, Class, Level, T)) :-
|
||||
T is HP-5.
|
||||
|
||||
status(character(Name, Class, Level, HP)) :-
|
||||
write(Name), write(' is a level '), write(Level), write(' '), write(Class), write(' with '), write(HP), write(' hitpoints.'), nl.
|
||||
|
||||
:- initialization(main).
|
||||
|
||||
main :-
|
||||
Gimli = character(gimli, fighter, 4, 35), status(Gimli),
|
||||
Legolas = character(legolas, ranger, 5, 30), status(Legolas),
|
||||
Gandalf = character(gandalf, wizard, 10, 25), status(Gandalf),
|
||||
Frodo = character(frodo, rogue, 2, 20), status(Frodo),
|
||||
write('legolas threw gimli, and gimli took 5 damage.'), nl,
|
||||
hit(Gimli, Thrown), status(Thrown),
|
||||
write('gandalf casts aid.'), nl,
|
||||
aid(Thrown, Aided), status(Aided),
|
||||
write('legolas leveled up.'), nl,
|
||||
levelup(Legolas, Leveled), status(Leveled).
|
9
examples/basics/backtracking.pl
Normal file
9
examples/basics/backtracking.pl
Normal file
|
@ -0,0 +1,9 @@
|
|||
leq(0, _).
|
||||
leq(s(X), s(Y)) :- leq(X, Y).
|
||||
|
||||
:- initialization(main).
|
||||
|
||||
main :-
|
||||
leq(X, s(s(s(0)))),
|
||||
write(X), nl,
|
||||
fail.
|
9
examples/basics/cut.pl
Normal file
9
examples/basics/cut.pl
Normal file
|
@ -0,0 +1,9 @@
|
|||
leq(0, _).
|
||||
leq(s(X), s(Y)) :- leq(X, Y).
|
||||
|
||||
:- initialization(main).
|
||||
|
||||
main :-
|
||||
leq(X, s(s(s(0)))), !,
|
||||
write(X), nl,
|
||||
fail.
|
15
examples/basics/disjunction.pl
Normal file
15
examples/basics/disjunction.pl
Normal file
|
@ -0,0 +1,15 @@
|
|||
likes(alice, pizza).
|
||||
likes(alice, pasta).
|
||||
likes(bob, pasta).
|
||||
|
||||
likes_italian_food(Person) :-
|
||||
likes(Person, pizza) ;
|
||||
likes(Person, pasta).
|
||||
|
||||
:- initialization(main).
|
||||
|
||||
main :-
|
||||
likes_italian_food(alice),
|
||||
write('Alice likes Italian food.'), nl,
|
||||
likes_italian_food(bob),
|
||||
write('Bob likes Italian food.'), nl.
|
20
examples/basics/equality.pl
Normal file
20
examples/basics/equality.pl
Normal file
|
@ -0,0 +1,20 @@
|
|||
check_equal(X, Y) :-
|
||||
X = Y,
|
||||
write('X = Y succeeded'), nl.
|
||||
|
||||
check_identical(X, Y) :-
|
||||
X == Y, !,
|
||||
write('X == Y succeeded'), nl.
|
||||
|
||||
check_identical(_, _) :-
|
||||
write('X == Y failed'), nl.
|
||||
|
||||
:- initialization(main).
|
||||
|
||||
main :-
|
||||
check_identical(A, 13),
|
||||
check_equal(A, 13),
|
||||
check_identical(A, 13),
|
||||
check_equal(42, 42),
|
||||
check_identical(42, 42).
|
||||
|
11
examples/basics/forall.pl
Normal file
11
examples/basics/forall.pl
Normal file
|
@ -0,0 +1,11 @@
|
|||
likes(alice, pizza).
|
||||
likes(alice, pasta).
|
||||
likes(bob, pasta).
|
||||
|
||||
:- initialization(main).
|
||||
|
||||
main :-
|
||||
forall(likes(X, pizza), X = alice),
|
||||
write('Only alice likes pizza.'), nl,
|
||||
forall(likes(X, pizza), X = bob),
|
||||
write('Bob should not like pizza.'), nl.
|
17
examples/basics/fraternity.pl
Normal file
17
examples/basics/fraternity.pl
Normal file
|
@ -0,0 +1,17 @@
|
|||
age(robespierre, 25).
|
||||
age(danton, 29).
|
||||
age(marat, 35).
|
||||
age(camus, 22).
|
||||
age(desmoulins, 19).
|
||||
|
||||
eligible_for_event(Person) :-
|
||||
age(Person, Age),
|
||||
between(20, 30, Age).
|
||||
|
||||
:- initialization(list_eligible_members).
|
||||
|
||||
list_eligible_members :-
|
||||
eligible_for_event(Person),
|
||||
write('Citizen '), write(Person), write(' is eligible for the event.'), nl,
|
||||
fail.
|
||||
|
31
examples/basics/liberty.pl
Normal file
31
examples/basics/liberty.pl
Normal file
|
@ -0,0 +1,31 @@
|
|||
:- dynamic declaration/1.
|
||||
|
||||
add_declaration_first(NewDecl) :-
|
||||
asserta(declaration(NewDecl)).
|
||||
|
||||
add_declaration_last(NewDecl) :-
|
||||
assertz(declaration(NewDecl)).
|
||||
|
||||
database :-
|
||||
add_declaration_first('Man is born free, and everywhere he is in chains.'),
|
||||
retract(declaration(_)),
|
||||
add_declaration_last('The revolution devours its own children.'),
|
||||
add_declaration_first('I disapprove of what you say, but I will defend to the death your right to say it.'),
|
||||
add_declaration_first('Give me Liberty, or give me Death!'),
|
||||
add_declaration_last('So this is how liberty dies, with thunderous applause.').
|
||||
|
||||
show_declarations :-
|
||||
declaration(Decl),
|
||||
write(Decl), nl,
|
||||
fail.
|
||||
|
||||
show_declarations.
|
||||
|
||||
:- initialization(main).
|
||||
|
||||
main :-
|
||||
database,
|
||||
show_declarations,
|
||||
retractall(declaration(_)),
|
||||
show_declarations.
|
||||
|
22
examples/basics/unification.pl
Normal file
22
examples/basics/unification.pl
Normal file
|
@ -0,0 +1,22 @@
|
|||
grade(alice, a).
|
||||
grade(bob, b).
|
||||
grade(carol, a).
|
||||
grade(dave, c).
|
||||
|
||||
got_an_a(Student) :-
|
||||
grade(Student, Grade),
|
||||
Grade = a.
|
||||
|
||||
did_not_get_an_a(Student) :-
|
||||
grade(Student, Grade),
|
||||
Grade \= a.
|
||||
|
||||
:- initialization(main).
|
||||
|
||||
main :-
|
||||
write("While "),
|
||||
got_an_a(X),
|
||||
write(X), write(" got an A, "), fail;
|
||||
write("but "),
|
||||
did_not_get_an_a(Y),
|
||||
write(Y), write(" did not get an A, "), fail; write("unfortunately."), nl.
|
1
examples/basics/write.pl
Normal file
1
examples/basics/write.pl
Normal file
|
@ -0,0 +1 @@
|
|||
:- initialization(main). main :- write('gpl zegt: '), groet(wereld), nl. groet(X) :- write(dag(X)).
|
10
examples/dcg/palimdrome.pl
Normal file
10
examples/dcg/palimdrome.pl
Normal file
|
@ -0,0 +1,10 @@
|
|||
palindrome --> [].
|
||||
palindrome --> [_].
|
||||
palindrome --> [X], palindrome, [X].
|
||||
|
||||
:- initialization(main).
|
||||
|
||||
main :-
|
||||
string_chars("hellolleh", Chars),
|
||||
phrase(palindrome, Chars).
|
||||
|
10
examples/dcg/tree.pl
Normal file
10
examples/dcg/tree.pl
Normal file
|
@ -0,0 +1,10 @@
|
|||
inorder(nil) --> [].
|
||||
inorder(node(L, N, R)) --> inorder(L), [N], inorder(R).
|
||||
|
||||
:- initialization(main).
|
||||
|
||||
main :-
|
||||
T = node(node(nil, b, node(nil, c, nil)), a, node(nil, d, nil)),
|
||||
phrase(inorder(T), Names),
|
||||
write(Names), nl.
|
||||
|
53
examples/lists/merlin.pl
Normal file
53
examples/lists/merlin.pl
Normal file
|
@ -0,0 +1,53 @@
|
|||
% Merlin's Potion lab
|
||||
|
||||
:- dynamic ingredient/1.
|
||||
|
||||
% Rules of the game
|
||||
|
||||
% Add a new ingredient if it's not already present
|
||||
add_ingredient(Item) :-
|
||||
\+ ingredient(Item),
|
||||
assertz(ingredient(Item)),
|
||||
write('Added ingredient: '), write(Item), nl.
|
||||
|
||||
% Use an ingredient (remove it from memory)
|
||||
use_ingredient(Item) :-
|
||||
ingredient(Item),
|
||||
retract(ingredient(Item)),
|
||||
write('Used ingredient: '), write(Item), nl.
|
||||
|
||||
% Make a potion from two ingredients
|
||||
make_potion(Item1, Item2) :-
|
||||
ingredient(Item1),
|
||||
ingredient(Item2),
|
||||
Item1 \= Item2,
|
||||
retract(ingredient(Item1)),
|
||||
retract(ingredient(Item2)),
|
||||
write('You mixed '), write(Item1), write(' and '), write(Item2),
|
||||
write(' to create a potion!'), nl.
|
||||
|
||||
% Show what's left
|
||||
show_ingredients :-
|
||||
findall(X, ingredient(X), List),
|
||||
write('Remaining ingredients: '), write(List), nl.
|
||||
|
||||
% Reset lab
|
||||
reset_lab :-
|
||||
retractall(ingredient(_)),
|
||||
write('Potion lab reset.'), nl.
|
||||
|
||||
% Merlin's recipes
|
||||
|
||||
stock :-
|
||||
add_ingredient(wolfsbane),
|
||||
add_ingredient(mandrake),
|
||||
add_ingredient(unicorn_blood),
|
||||
add_ingredient(phoenix_feather),
|
||||
add_ingredient(dittany).
|
||||
|
||||
brew :-
|
||||
stock,
|
||||
make_potion(wolfsbane, mandrake),
|
||||
show_ingredients.
|
||||
|
||||
:- initialization(brew).
|
74
examples/lists/zebra.pl
Normal file
74
examples/lists/zebra.pl
Normal file
|
@ -0,0 +1,74 @@
|
|||
%% houses(-Solution)
|
||||
% @param Solution is a list of houses that satisfy all constraints.
|
||||
% @author Folklore attributes this puzzle to Einstein
|
||||
% @see http://en.wikipedia.org/wiki/Zebra_Puzzle
|
||||
|
||||
/* Houses logical puzzle: who owns the zebra and who drinks water?
|
||||
|
||||
1) Five colored houses in a row, each with an owner, a pet, cigarettes, and a drink.
|
||||
2) The English lives in the red house.
|
||||
3) The Spanish has a dog.
|
||||
4) They drink coffee in the green house.
|
||||
5) The Ukrainian drinks tea.
|
||||
6) The green house is next to the white house.
|
||||
7) The Winston smoker has a serpent.
|
||||
8) In the yellow house they smoke Kool.
|
||||
9) In the middle house they drink milk.
|
||||
10) The Norwegian lives in the first house from the left.
|
||||
11) The Chesterfield smoker lives near the man with the fox.
|
||||
12) In the house near the house with the horse they smoke Kool.
|
||||
13) The Lucky Strike smoker drinks juice.
|
||||
14) The Japanese smokes Kent.
|
||||
15) The Norwegian lives near the blue house.
|
||||
|
||||
Who owns the zebra and who drinks water?
|
||||
*/
|
||||
|
||||
zebra_owner(Owner) :-
|
||||
houses(Hs),
|
||||
member(h(Owner,zebra,_,_,_), Hs).
|
||||
|
||||
water_drinker(Drinker) :-
|
||||
houses(Hs),
|
||||
member(h(Drinker,_,_,water,_), Hs).
|
||||
|
||||
houses(Hs) :-
|
||||
% each house in the list Hs of houses is represented as:
|
||||
% h(Nationality, Pet, Cigarette, Drink, Color)
|
||||
length(Hs, 5), % 1
|
||||
member(h(english,_,_,_,red), Hs), % 2
|
||||
member(h(spanish,dog,_,_,_), Hs), % 3
|
||||
member(h(_,_,_,coffee,green), Hs), % 4
|
||||
member(h(ukrainian,_,_,tea,_), Hs), % 5
|
||||
next(h(_,_,_,_,green), h(_,_,_,_,white), Hs), % 6
|
||||
member(h(_,snake,winston,_,_), Hs), % 7
|
||||
member(h(_,_,kool,_,yellow), Hs), % 8
|
||||
Hs = [_,_,h(_,_,_,milk,_),_,_], % 9
|
||||
Hs = [h(norwegian,_,_,_,_)|_], % 10
|
||||
next(h(_,fox,_,_,_), h(_,_,chesterfield,_,_), Hs), % 11
|
||||
next(h(_,_,kool,_,_), h(_,horse,_,_,_), Hs), % 12
|
||||
member(h(_,_,lucky,juice,_), Hs), % 13
|
||||
member(h(japanese,_,kent,_,_), Hs), % 14
|
||||
next(h(norwegian,_,_,_,_), h(_,_,_,_,blue), Hs), % 15
|
||||
member(h(_,_,_,water,_), Hs), % one of them drinks water
|
||||
member(h(_,zebra,_,_,_), Hs). % one of them owns a zebra
|
||||
|
||||
next(A, B, Ls) :- append(_, [A,B|_], Ls).
|
||||
next(A, B, Ls) :- append(_, [B,A|_], Ls).
|
||||
|
||||
/** <examples>
|
||||
|
||||
?- zebra_owner(Owner).
|
||||
|
||||
?- water_drinker(Drinker).
|
||||
|
||||
?- houses(Houses).
|
||||
|
||||
*/
|
||||
|
||||
main :- findall(Houses, houses(Houses), Results), write(Results), nl.
|
||||
|
||||
:- initialization(main).
|
||||
|
||||
/* source: SWISH https://swish.swi-prolog.org/example/houses_puzzle.pl */
|
||||
|
28
examples/meta/mib.pl
Normal file
28
examples/meta/mib.pl
Normal file
|
@ -0,0 +1,28 @@
|
|||
% Old mag steeds door New vervangen worden
|
||||
mib(Old, New, Old, New).
|
||||
|
||||
% Een term blijft enkel behouden als het een attoom is
|
||||
% (dat is, niet compound), en als het niet Old is
|
||||
mib(Old, _, Term, Term) :-
|
||||
atomic(Term),
|
||||
Term \= Old.
|
||||
|
||||
% Voor een samengestelde Term
|
||||
mib(Old, New, Pre, Post) :-
|
||||
compound(Pre),
|
||||
functor(Pre, F, N), % Pre heeft naam F en arriteit N
|
||||
functor(Post, F, N), % Post is term met zelfde naam (F) en arriteit (N)
|
||||
mib(N, Old, New, Pre, Post).
|
||||
|
||||
% Extra predicaat om de argumenten te vervangen van een samengestelde term
|
||||
%
|
||||
% N = het nr van het argument (strikt positief)
|
||||
mib(0, _, _, _, _) :- !. % Argument 0 bestaat niet, als we hier komen zijn we klaar.
|
||||
|
||||
mib(N, Old, New, Pre, Post) :-
|
||||
arg(N, Pre, ArgPre), % neem het N-de argument
|
||||
mib(Old, New, ArgPre, ArgPost), % vertaal het
|
||||
arg(N, Post, ArgPost), % unificeer het met het N-de argument van output
|
||||
N1 is N-1,
|
||||
mib(N1, Old, New, Pre, Post). % Herhaal voor argument N-1
|
||||
|
5
examples/program.pl
Normal file
5
examples/program.pl
Normal file
|
@ -0,0 +1,5 @@
|
|||
:- initialization(main).
|
||||
|
||||
main :- write(10),
|
||||
nl,
|
||||
write(hello(world)).
|
Reference in a new issue