% -*- prolog -*- % constants: stone grass carrot beef dead_rabbit cow rabbit human is_meat(beef). is_meat(dead_rabbit). is_meat(dead_human). % :- pred can_eat(animal, food). % :- mode can_eat(in, in) is semidet. % (could also be :- mode can_eat(in, out) is multi.) can_eat(cow, grass). can_eat(rabbit, carrot). can_eat(human, carrot). can_eat(human, Meat) :- is_meat(Meat). % :- pre eat(animal, food, animal2). % :- mode eat(in, in, out) is semidet. eat(Animal, Food, Animal2) :- (Animal_kind, Animal_energy) = Animal, (Food_kind, Food_energy) = Food, can_eat(Animal_kind, Food_kind), Animal2_energy is Animal_energy + Food_energy, Animal2 = (Animal_kind, Animal2_energy). % :- pred slaughter(animal, food) % :- mode slaughter(in, out) is det. % the in argument must be an animal slaughter_helper(cow, beef). slaughter_helper(human, dead_human). slaughter_helper(rabbit, dead_rabbit). slaughter((Animal_kind, Energy), (Food_kind, Energy)) :- slaughter_helper(Animal_kind, Food_kind). should_work :- Grass = (grass, 5), Carrot = (carrot, 10), A_rabbit = (rabbit, 100), A_cow = (cow, 1000), A_human = (human, 300), Another_human = (human, 350), eat(A_rabbit, Carrot, A_rabbit2), eat(A_cow, Grass, A_cow2), slaughter(A_rabbit2, A_dead_rabbit), slaughter(A_cow2, A_beef), eat(A_human, Carrot, A_human2), eat(A_human2, Carrot, A_human3), eat(A_human3, A_beef, A_human4), eat(A_human4, A_dead_rabbit, A_human5), slaughter(A_human5, A_dead_human), eat(Another_human, A_dead_human, Another_human2), % the 3 below should fail % => this implementation doesn't fulfill GOAL #1 eat((human, 300), A_beef, _), % a_beef is already eaten eat(A_cow, (grass, 5), _), % a_cow is dead, it can't eat slaughter(A_cow, _), % a_cow is dead, it can't be slaughtered again (_, 1785) = Another_human2. fail01 :- slaughter((cow, 10), Meat1), eat(Meat1, (grass, 5), _) .% meat (food) can't eat fail02 :- slaughter((cow, 10), Meat2), slaughter(Meat2, _) .% meat (food) can't be slaughtered fail03 :- eat((carrot, 10), (grass, 5), _) .% vegetable (food) can't eat fail04 :- slaughter((carrot, 10), _) .% vegetable (food) can't be slaughtered fail05 :- eat((cow, 10), (carrot, 10), _) .% cow do not eat carrot fail06 :- slaughter((cow, 10), Meat3), eat((cow, 10), Meat3, _) .% cow do not eat beef fail07 :- eat((human, 300), (cow, 10), _) .% can't eat live animals fail08 :- eat((human, 300), (grass, 5), _) .% human do not eat grass must_fail(F) :- (call(F), !, write(F), write(' failed'), fail) ; true. these_should_fail :- must_fail(fail00), must_fail(fail01), must_fail(fail02), must_fail(fail03), must_fail(fail04), must_fail(fail05), must_fail(fail06), must_fail(fail07). % some remarks: % errors % - nothing ensures a killed cow doesn't eat anymore % - nothing ensures A_beef or A_dead_rabbit is eaten only once % - nothing ensures A_human is not used when A_human2 exists % no compile time checks % - eat(some_food, _, _) % - eat(_, animal, _) % - slaughter(some_food, _) % - eat(A_human, Grass) % - eat(A_cow, Carrot) % - eat(A_cow, A_beef)