在GOAL中使用带有递归调用的/ 3的集合出错了,为什么?

时间:2014-08-08 07:15:50

标签: xml prolog prolog-setof

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

背景信息:

我使用SWI-Prolog load_xml()加载一个xml文件来获取递归 list元素(参见示例中的testelement)。然后我想看看 此列表中的特定元素(在xml树中) 使用findall/3sort/2结合使用,效果很好。但如果 我使用setof/3,我错过了一个结果。我认为setof/3有问题 在askElement/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代码:}

2 个答案:

答案 0 :(得分:2)

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

?- [library(xpath)].
true.

?- testElement(E), xpath(E, //head//title(text), T).
...
T = 'Spaghetti Bolognese' ;
...
T = 'Erbsensuppe' ;
false.

答案 1 :(得分: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']].

关于编程风格的注释,在 atoms 中使用下划线代替CamelCase以获取代码可读性。例如。 ask_element代替askElement。另一方面,对于变量,经常使用CamelCase。