prologinstantiation-error

Arguments are not sufficiently instantiated while trying to get combinations


I'm learning Prolog and I want to build a recipe recommendation based on calories. So base on how many calories you put as input, I want to return the combinations of a breakfast, a lunch, and a dinner.

The breakfast, the dinner, and the lunch are composed differently, so in this case, the breakfast is composed of a drink and a dish, and the dish itself is composed of cereal, a fruit or a vegetable, and an animal origin food.

Right now, I'm trying to get all the possible breakfast I have the following Prolog code

dish([Cereal, FruitOrVegetable, AnimalOrigin], Calories) :- 
  cereal(Cereal, CerealCalories),
  (
      fruit(FruitOrVegetable, FruitOrVegetableCalories); 
      vegetable(FruitOrVegetable, FruitOrVegetableCalories)
  ),
  animalOrigin(AnimalOrigin, AnimalOriginCalories),
  Calories >= CerealCalories + FruitOrVegetableCalories + AnimalOriginCalories.

breakfast([Drink, Dish], Calories) :-
  drink(Drink, DrinkCalories),
  dish(Dish, DishCalories),
  Calories >= DrinkCalories + DishCalories.

If I execute the dish function, just with 600 calories it works, it returns the combination of the given food, but when I tried to implement the same logic to compose the breakfast function it throws me the following error

Arguments are not sufficiently instantiated

And I search for a while, and I found that it because of a var that is inst initialized but I didn't found the origin of the problem.

An example of the declaration of the knowledge data base is

cereal(flakes, 386).
fruit(apple, 52).
vegetable(broccoli, 31).
animalOrigin(chicken_breast, 134).
drink(water, 0).

where the first is the name of the food, and the second the calories


Solution

  • The problem is that you call

    dish(Dish, DishCalories)
    

    from breakfast/2, but DishCalories is at that point an uninstantiated variable.

    So when the Prolog Processor hits

    Calories >= CerealCalories + FruitOrVegetableCalories + AnimalOriginCalories.
    

    the variable Calories, which is the same as the earlier DishCalories, will be uninstantiated. There is nothing to compare!

    You can either:

    :- use_module(library(clpfd)).
    
    dish([Cereal, FruitOrVegetable, AnimalOrigin], Calories) :- 
      cereal(Cereal, CerealCalories),
      (
          fruit(FruitOrVegetable, FruitOrVegetableCalories); 
          vegetable(FruitOrVegetable, FruitOrVegetableCalories)
      ),
      animalOrigin(AnimalOrigin, AnimalOriginCalories),
      %
      % Compare if we know enough, otherwise delay the decision on >=
      % and proceed optimistically
      %
      Calories #>=                    
         CerealCalories +              
         FruitOrVegetableCalories + 
         AnimalOriginCalories.
    
    breakfast([Drink, Dish], Calories) :-
      drink(Drink, DrinkCalories),
      dish(Dish, DishCalories),
      format("Calories: ~q, DrinkCalories: ~q, DishCalories: ~q~n", 
              [Calories,DrinkCalories,DishCalories]),
      Calories #>= DrinkCalories + DishCalories.
    

    And so:

    As usual:

    ?- dish(List,600).
    List = [flakes, apple, chicken_breast] ;
    List = [flakes, broccoli, chicken_breast].
    

    But this works too, now:

    ?- breakfast(List,600).
    Calories: 600, DrinkCalories: 0, DishCalories: _21370
    List = [water, [flakes, apple, chicken_breast]] ;
    Calories: 600, DrinkCalories: 0, DishCalories: _22506
    List = [water, [flakes, broccoli, chicken_breast]].
    

    If you don't even specify the Calories:

    Calories is a number larger than 572:

    ?- breakfast(List,Calories).
    Calories: _23482, DrinkCalories: 0, DishCalories: _23990
    List = [water, [flakes, apple, chicken_breast]],
    _25276 in 572..sup,
    Calories#>=_25276,
    Calories in 572..sup ;
    

    or Calories is a number larger than 551:

    Calories: _23482, DrinkCalories: 0, DishCalories: _26724
    List = [water, [flakes, broccoli, chicken_breast]],
    _28010 in 551..sup,
    Calories#>=_28010,
    Calories in 551..sup.