0

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

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

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

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.

如果我执行菜功能,它只需要 600 卡路里,它会返回给定食物的组合,但是当我尝试实现相同的逻辑来组成早餐功能时,它会抛出以下错误

Arguments are not sufficiently instantiated

而且我搜索了一会儿,发现是因为一个 var 是 inst 初始化的,但是我没有找到问题的根源。

知识数据库声明的一个例子是

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

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

4

1 回答 1

1

问题是你打电话

dish(Dish, DishCalories)

breakfast/2, 但DishCalories此时是一个未实例化的变量。

所以当 Prolog 处理器命中时

Calories >= CerealCalories + FruitOrVegetableCalories + AnimalOriginCalories.

变量Calories与前面的相同DishCalories,将未实例化。没有什么可以比较的!

您可以:

  • 计算热量总和dish/2并“将其传回”,这样就可以计算出饮料 + 磁盘的完整总和,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.
于 2021-03-27T07:38:07.963 回答