【问题标题】:How can i tell if an object is unique如何判断一个对象是否唯一
【发布时间】:2013-03-09 14:39:09
【问题描述】:

我只是无法解决我在 prolog 中遇到的这个问题。才刚刚开始,但我似乎无法找到一种方法来找出一个对象是否是唯一的。这是我的代码:

/* (Student Name, Student Number)*/
Student(stuart, 11234).
Student(ross, 11235).
Student(rose, 11236).
Student(stuart, 11237).

我怎样才能知道一个学生是否是独一无二的。以斯图尔特为例,有两个学生叫斯图尔特,所以斯图尔特不是唯一的。我如何编写一个程序来判断它是否是另一个名为 Stuart 的学生。

我已经尝试在这方面花费了很多时间,但我似乎无法处理原来的 Stuart 而不是另一个 Stuart,因为我无法排除我想要找出的那个如果它是独一无二的。

感谢您的帮助。

【问题讨论】:

    标签: prolog logic unique


    【解决方案1】:

    使用您的数据库示例可以这样做

    unique(S) :-
        student(S, N), \+ (student(S, M), M \= N).
    

    因为它产生了

    ?- unique(S).
    S = ross ;
    S = rose ;
    false.
    

    一般来说,Prolog 的目标是存在的解决方案。然后,关于基数的预测需要语言中“不纯”部分的一些支持:nb_setarg 当我们需要有效跟踪基数时,它目前是我们最好的朋友。

    使用这样的元谓词:

    %%  count_solutions(+Goal, ?C)
    %
    %   adapted from call_nth/2 for http://stackoverflow.com/a/14280226/874024
    %
    count_solutions(Goal, C) :-
        State = count(0, _), % note the extra argument which remains a variable
        (   Goal,
            arg(1, State, C1),
            C2 is C1 + 1,
            nb_setarg(1, State, C2),
            fail
        ;   arg(1, State, C)
        ).
    
    :- meta_predicate count_solutions(0, ?).
    

    你可以不考虑第二个参数来解决问题

    unique(S) :-
        student(S, _), count_solutions(student(S, _), 1).
    

    同样的谓词可以使用来自 library(aggregate) 的 aggregate_all(count, student(S,_), 1),但是这样的库目前在内部构建一个列表,那么你可以认为 Peter 的答案更容易实现。

    【讨论】:

    • 谢谢,我确定有一种方法可以使用 \+,但我猜你的解决方案可以很好地处理它:)
    【解决方案2】:

    可能有很多方法可以解决这个问题,但我会这样做:

    % a student has a name and a number
    student(stuart, 11234).
    student(ross, 11235).
    student(rose, 11236).
    student(stuart, 11237).
    

    这段代码说“找到一个长度与有名字的学生数量相同的列表”,然后“使 Count 与列表的长度相同”:

    % for every student name there is an associated count of how many times 
    %   that name appears
    number_students(Name, Count) :-
        findall(_, student(Name, _), Students),
        length(Students, Count).
    

    这个谓词只有在 number_students 为 1 时才为真:

    % a student name is unique (appears once and only once) is the 
    %  number_students count is 1
    unique_student(Name) :-
        number_students(Name, 1).
    

    测试:

    12 ?- unique_student(ross).
    true.
    
    13 ?- unique_student(rose).
    true.
    
    14 ?- unique_student(bob).
    false.
    
    15 ?- unique_student(stuart).
    false.
    

    这是解决问题的一种简单方法,但它不是一个很棒的 Prolog 解决方案,因为您不能说“给我一个唯一的学生姓名”之类的话并获得所有唯一的名称。

    【讨论】:

      【解决方案3】:

      您拥有的代码上有一些 cmets。这不是事实:

      Student(Ross).
      

      这是两个不同的事实(至少在 SWI-Prolog 中):

      student(ross).
      student('Ross').
      

      换句话说,谓词名称必须以小写字母开头,而以大写字母开头的标识符表示变量,而不是原子。您可以将任何字符串放在单引号中以使其成为有效的原子。

      现在这个问题已经解决了,不清楚你的目标是什么。你打算怎么处理你独特的学生?你怎么知道第一个是你要找的,而不是第二个?为什么不使用学生编号(至少在您的示例中,两个 Stuarts 似乎有不同的编号)?

      【讨论】:

      • 感谢您花时间解决我的问题。是的,你说得对,我的代码无效。这只是一个关于如何做独特事情的例子。我想知道是否有一种方法可以表示学生是否独特。是的,我可以使用学号,但我真的很想知道一种方法,我可以判断某人是否是独一无二的。我要对独特的学生做的是判断它是否独特
      猜你喜欢
      • 2015-03-01
      • 1970-01-01
      • 2011-11-28
      • 2012-12-03
      • 2012-10-16
      • 2018-05-06
      • 1970-01-01
      • 2019-02-11
      相关资源
      最近更新 更多