Counter-intuitive behavior of min_member/2

后端 未结 6 1300
一个人的身影
一个人的身影 2021-01-04 16:40

min_member(-Min, +List)

True when Min is the smallest member in the standard order of terms. Fails if List is empty.

?- min_member(3, [1,2,X]).
X = 3         


        
6条回答
  •  小鲜肉
    小鲜肉 (楼主)
    2021-01-04 16:44

    I hope I am not off-topic with this third answer. I did not edit one of the previous two as I think it's a totally different idea. I was wondering if this undesired behaviour:

    ?- min_member(X, [A, B]), A = 3, B = 2.
    X = A, A = 3,
    B = 2.
    

    can be avoided if some conditions can be postponed for the moment when A and B get instantiated.

    promise_relation(Rel_2, X, Y):-
        call(Rel_2, X, Y),
        when(ground(X), call(Rel_2, X, Y)),
        when(ground(Y), call(Rel_2, X, Y)).
    
    min_member_1(Min, Lst):-
        member(Min, Lst),
        maplist(promise_relation(@=<, Min), Lst).
    

    What I want from min_member_1(?Min, ?Lst) is to expresses a relation that says Min will always be lower (in the standard order of terms) than any of the elements in Lst.

    ?- min_member_1(X, L), L = [_,2,3,4], X = 1.
    X = 1,
    L = [1, 2, 3, 4] .
    

    If variables get instantiated at a later time, the order in which they get bound becomes important as a comparison between a free variable and an instantiated one might be made.

    ?- min_member_1(X, [A,B,C]), B is 3, C is 4, A is 1.
    X = A, A = 1,
    B = 3,
    C = 4 ;
    false.
    ?- min_member_1(X, [A,B,C]), A is 1, B is 3, C is 4.
    false.
    

    But this can be avoided by unifying all of them in the same goal:

    ?- min_member_1(X, [A,B,C]), [A, B, C] = [1, 3, 4].
    X = A, A = 1,
    B = 3,
    C = 4 ;
    false.
    

    Versions

    If the comparisons are intended only for instantiated variables, promise_relation/3 can be changed to check the relation only when both variables get instantiated:

    promise_relation(Rel_2, X, Y):-
        when((ground(X), ground(Y)), call(Rel_2, X, Y)).
    

    A simple test:

    ?- L = [_, _, _, _], min_member_1(X, L), L = [3,4,1,2].
    L = [3, 4, 1, 2],
    X = 1 ;
    false.
    

    ! Edits were made to improve the initial post thanks to false's comments and suggestions.

提交回复
热议问题