尝试获取组合时参数未充分实例化

Arguments are not sufficiently instantiated while trying to get combinations

我正在学习 Prolog,我想根据卡路里构建食谱推荐。因此,根据您输入的卡路里数量,我想 return 早餐、午餐和晚餐的组合。

早餐、晚餐和午餐的组成不同,所以在这种情况下,早餐由饮料和菜肴组成,菜肴本身由麦片、水果或蔬菜组成,并且一种动物源性食品。

现在,我正在尝试获取所有可能的早餐我有以下序言代码

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.

如果我执行 dish 函数,只需要 600 卡路里就可以了,它 return 是给定食物的组合,但是当我尝试实现相同的逻辑来组合 breakfast 函数时,它抛出了我以下错误

Arguments are not sufficiently instantiated

然后找了一会儿,发现是因为inst初始化了一个var,但是没找到问题的根源。

知识库声明的一个例子是

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

第一个是食物的名称,第二个是卡路里

问题是你打电话

dish(Dish, DishCalories)

来自 breakfast/2,但是 DishCalories 在那个时候是一个未实例化的变量。

所以当 Prolog 处理器命中时

Calories >= CerealCalories + FruitOrVegetableCalories + AnimalOriginCalories.

与之前的DishCalories相同的变量Calories将被取消实例化。没有什么可比较的!

您可以:

  • 计算dish/2中的热量并“传回”,这样一个完整的 可以计算 drink + disk 的总和 breakfast/2,然后像在其他编程语言中一样与 Calories 进行比较;或
  • 使用不需要“立即计算”并在内部构造对应于部分填充表达式的数据结构的约束逻辑编程,当知道更多时可以“稍后”评估(并且可能失败):
:- 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.

等等:

像往常一样:

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

但现在这也行得通:

?- 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]].

如果您甚至不指定 Calories:

Calories是大于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 ;

Calories是大于551的数字:

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