Search code examples
listprologrecipe

recipe function in prolog


Say you have recipes in prolog saved as

step(meal name, stepnumber, stepexaplanation, ingredients (list) , utensils). 

So for every meal name you have multiple steps with all the explanations to make the meal. How would you then make a function that calls getStepText(X,Y,Z).? So if you ask:

?- getStepText('pancakes',2,Y). 

It will return the text of the second step for the meal pancakes.


Solution

  • step('pancakes', 1, 'mix butter and sugar in a bowl', [butter, sugar], [bowl]). 
    step('pancakes', 2, 'add eggs', [eggs], []). 
    step('pancakes', 3, 'mix flour and bakingpowder', [flour, baking_powder], []). 
    
    getStepText(Dish,Num,Text):-
        step(Dish, Num, Text, _, _).
    
    ?- getStepText('pancakes',2,Y). 
    Y = 'add eggs' ;
    false.
    

    If you are using SWI Prolog you can use the inbuild predicate findall/3 to find all of your steps. Don't forget to sort them.

    getSteps(X,S):- 
        findall(N,step(X,N,_,_,_),Bag), 
        sort(Bag,S). 
    
    ?- getSteps('pancakes',Y). 
    Y = [1, 2, 3] ;
    false.
    

    If you don't want to use findall/3 you can define a helper predicate getSteps/3. This predicate assumes all steps are incremental and start with 1.

    getSteps(X,S):- 
        getSteps(X,S,1).
    
    getSteps(X, [], N):-
        \+ step(X, N, _, _, _). 
    getSteps(X, [N|T], N):-
        step(X, N, _, _, _),
        NN is N+1,
        getSteps(X, T, NN).
    
    ?- getSteps('pancakes',Y). 
    Y = [1, 2, 3] ;
    false.
    

    Explanation: you basically run a counter N from 1 (set when calling) until you can't find any step with the current number N. The first rule tests for the end: if you don't have a step for the current N "return" the empty list [].

    Otherwise when you find a step with the number N, try to find the steplist T for the next value NN (which is N+1) and - once found - put N on top of the list T.