Can you write between/3 in pure prolog?

后端 未结 2 712
不知归路
不知归路 2020-11-30 15:19

I\'ve been trying to understand how to produce a series of values from a Prolog predicate on backtracking. The builtin predicate between/3 will generate all the

相关标签:
2条回答
  • 2020-11-30 15:31

    What you're really asking is how to create a choice point. You get a solution whenever you have a successful unification. That's what happens in @seanmcl's first predicate:

    bet(N, M, K) :- N =< M, K = N.
    

    To get a choice point, you need to have alternatives. There are only two ways to get an alternative in Prolog: with an explicit "or": ;, or by supplying another rule. @seanmcl's code gives another rule, which is idiomatic for this situation.

    To give another example, member/2 generates a solution for every item in the list, but there's no magic C function needed, just two rules:

    member(X, [X|_]).
    member(X, [_|Xs]) :- member(X, Xs).
    

    Let's look at what happens here with member(X, [1,2]). First, the first rule is used and [X|_] is unified with [1,2], producing X=1, _=[2]. This is a successful unification, so a solution is generated. If this fails (such as by you pressing ; at the console), backtracking is initiated. The next choice point is between the two rules, so the next rule is entered. [_|Xs] unifies with [1,2], producing the binding Xs=[2] and then member(X, [2]) is called. Upon re-entry, the same decisions are available to be made again, so the first rule member(X, [X|_]) is applied and the X=2 binding is produced. This is a solution. If you backtrack again, you'll get a harmless failure because neither of the rules unify with [].

    I hope this helps make sense of the situation a little bit.

    0 讨论(0)
  • 2020-11-30 15:40
    bet(N, M, K) :- N =< M, K = N.
    bet(N, M, K) :- N < M, N1 is N+1, bet(N1, M, K).
    

    In action:

    $ swipl
    ?- [bet].
    % bet compiled 0.00 sec, 1,064 bytes
    true.
    
    ?- bet(1,5, K).
    K = 1 n
    K = 2 n
    K = 3 n
    K = 4 n
    K = 5 n
    false.
    

    If you use a cut, you can prevent the final search failure, and recover the exact builtin between/3 behavior:

    bet(N, M, K) :- N < M, K = N.
    bet(N, M, K) :- N == M, !, K = N.
    bet(N, M, K) :- N < M, N1 is N+1, bet(N1, M, K).
    

    In action:

    ?- [bet].
    % bet compiled 0.00 sec, 416 bytes
    true.
    
    ?- between(1,5,K).
    K = 1 n
    K = 2 n
    K = 3 n
    K = 4 n
    K = 5.
    
    ?- [bet].
    % bet compiled 0.00 sec, 240 bytes
    true.
    
    ?- bet(1,5,K).
    K = 1 n
    K = 2 n
    K = 3 n
    K = 4 n
    K = 5.
    
    0 讨论(0)
提交回复
热议问题