1

我在使用时遇到问题setof/3,缺少一些结果。

上下文:

我使用 SWI-Prolog load_xml() 加载一个 xml 文件以获取递归列表元素(参见示例中的 testelement)。然后我想在这个列表中查找特定的元素(在 xml 树中)。结合使用
,效果很好。但如果我使用,我会错过一个结果。我想这是由于递归调用获取/保留元素而导致的问题?知道将元素从递归列表中取出的另一种解决方案吗?findall/3sort/2setof/3setof/3askElement/3

我的测试代码:

testElement([element('recipeml',[version=0.5], 
    [element('recipe',[],
        [element('head',[],
            [element('title',[],['Spaghetti Bolognese']
            )]
        ),
        element('ing-div',[type=titled], 
            [element('title',[],['sauce']),
             element('ingredients',[],
                [element('ing',[],
                    [element('item',[],['hackfleisch']),
                     element('item',[],['fleischtomaten']),
                     element('item',[],['zwiebeln']),
                     element('item',[],['sellerie']
                    )]
                )]
            )]
        )]
    ),
    element('recipe',[],
        [element('head',[],
            [element('title',[],['Erbsensuppe']
            )]
        ),
        element('ing-div',[type=titled], 
            [element('title',[],['elementar']),
             element('ingredients',[],
                [element('ing',[],
                    [element('item',[],['sahne']),
                     element('item',[],['erbsen']),
                     element('item',[],['gemüsebrühe']
                    )]
                )]
            )]
        )]
    )] 
)]).

askElement(Name, Child, Parent) :-
    (
        member( element(Name,_,Child),Parent)
    ;
        member( element(_,_,NewParent),Parent),
        [_|_] = NewParent,
        askElement(Name, Child, NewParent)
    ).

allRecipes_findall(RecipeName) :-
    testElement(Knot),
    findall(TmpR,(askElement('head',HKnot,Knot),askElement('title',TmpR,HKnot)),Bag),
    sort(Bag, RecipeName).

allRecipes_setof(RecipeName) :-
    testElement(Knot),
    setof(TmpR,(askElement('head',HKnot,Knot),askElement('title',TmpR,HKnot)),RecipeName).

我的输出:

3 ?- allRecipes_findall(X).
X = [['Erbsensuppe'], ['Spaghetti Bolognese']].

4 ?- allRecipes_setof(X).
X = [['Erbsensuppe']] 

我希望在这两种情况下我都能得到

X = [['Erbsensuppe'], ['Spaghetti Bolognese']].

怎么了?

提前谢谢了!

PS:非常欢迎对我(第一次尝试)Prolog 代码的每条评论/评论:}

4

2 回答 2

2

Paulo 已经就您当前的代码提供了大量建议。我在这里只是建议您在需要处理 XML 时利用 library( xpath )。它确实需要一些锻炼,但是你会得到很多功能的奖励......例如:

?- [library(xpath)].
true.

?- testElement(E), xpath(E, //head//title(text), T).
...
T = 'Spaghetti Bolognese' ;
...
T = 'Erbsensuppe' ;
false.
于 2014-08-08T12:53:22.923 回答
1

标准setof/3谓词为目标中自由变量的每个不同实例化提供了一个解决方案。使用您的代码原样给出:

?- allRecipes_findall(X).
X = [['Erbsensuppe'], ['Spaghetti Bolognese']].

?- allRecipes_setof(X).
X = [['Erbsensuppe']] ;
X = [['Spaghetti Bolognese']].

这就是预期的结果。但是,您可以setof/3通过使用运算符对它们进行存在量化来忽略自由变量^/2

allRecipes_setof(RecipeName) :-
    testElement(Knot),
    setof(TmpR,HKnot^(askElement('head',HKnot,Knot),askElement('title',TmpR,HKnot)),RecipeName).

findall/3通过此更改,您将获得与谓词相同的结果:

?- allRecipes_setof(X).
X = [['Erbsensuppe'], ['Spaghetti Bolognese']].

关于对您的编程风格的评论,为了代码的可读性,请在atom中使用下划线而不是 CamelCase。例如ask_element,而不是askElement. 另一方面,对于variables ,经常使用 CamelCase 。

于 2014-08-08T08:49:57.397 回答