Prolog:解析语义正确性的术语(模式匹配)

时间:2017-04-19 06:52:19

标签: list parsing prolog pattern-matching

我正在完成一项任务,我被困在了。我对prolog的经验很少,而且我正在学习基于在线资料和教科书的工作。

赋值的目的是生成一个谓词parse(),它能够检查给定的参数/术语是否具有以下形式,并在适当时返回true或false:

  • ((INT,INT),[(整数,浮点),(整数,浮点)...])

这是一个int对,后跟一个n大小的(int,float)对列表,两者都包含在一个元组中。

例如:

  • ((1,7),[(1,0.0),(2,0.5),(3,0.7),(4,0.8),(5,0.8),(6, 0.25),(7,0.3)])

有人能指出我正确的方向,从哪里开始吗?我在Prolog中从未这样做过。

我不是在寻找一个完整的编码答案,当然这是一个任务,但只是如何处理这个问题的一些方向。我没有声明性的编程背景,所以这是一个教育练习。

谢谢!

2 个答案:

答案 0 :(得分:1)

我们可以从观察开始,你所展示的是已经是一个有效的Prolog术语

?- T = ( (1, 7), [(1, 0.0), (2, 0.5), (3, 0.7), (4, 0.8), (5, 0.8), (6, 0.25), (7, 0.3)] ) .
T =  ((1, 7), [(1, 0.0),  (2, 0.5),  (3, 0.7),  (4, 0.8),  (5, 0.8),  (6, 0.25),  (7, 0.3)]).

因此,在这种情况下,不需要手动解析。通过解析,我们通常意味着将非结构化文本(例如字符或字符代码的简单列表)转换为结构化< / strong>代表。

Prolog 自动拒绝非语法有效的字词。所以,在你的情况下, if 你已经有了这样一个术语,只需说明持有的内容,以便它满足所有约束条件。

在Prolog中,首先考虑您可能希望用作有用基础的构建块通常很有用。例如,让我们描述一个(int,float)术语:

integer_float_tuple((I,F)) :- integer(I), float(F).

我们可以按如下方式使用它:

?- integer_float_tuple((3,4.5)).
true.

请注意:

  1. 首先,定义是不是真正的关系。例如,即使明确 解决方案,最常见的查询?- integer_float_tuple(T).也会失败
  2. 其次,不鼓励使用(A,B)形式的术语,因为(',')/2已用于Prolog中的许多其他内容。最好将这些对表示为I-F,使用(-)/2,这通常用于表示Prolog库中的
  3. 无论如何,我们可以使用以下内容构建此定义:

    good_term((Tuple,Tuples)) :-
            Tuple = (A,B),
            integer(A), integer(B),
            maplist(integer_float_tuple, Tuple).
    

    这说明了这些条款必须包含的所有内容,因此可以验证它们,但如上所述,不是生成它们。要概括此类谓词在所有方向上工作,请使用Prolog系统的CLP(FD)和CLP(R)约束。这将为您提供单调的定义,并满足我们期望从逻辑程序中获得的许多理想属性。

    此外,如果你真的想手动解析你的数据(而不是依赖Prolog内置的结构化术语概念),我有两个建议:< / p>

    首先,将以下指令添加到您的程序中:

    :- set_prolog_flag(double_quotes, chars).
    

    这使您可以使用双引号方便地编写字符列表。

    例如:

    ?- Cs = "abc".
    Cs = [a, b, c].
    

    这样的表示非常方便我们接下来要做的事情,即使用Prolog Definite Clause Grammars 解析这样的字符列表。

    我不会为你解决整个任务,但我会给你一个开始。我们可以从描述数字的含义开始:

    digit(D) --> [D], { char_type(D, digit) }.
    

    我们在phrase/2接口谓词中使用这样的语法。例如:

    ?- phrase(digit(D), "5").
    D = '5'.
    

    在此定义的基础上,让我们描述数字的列表

    digits([]) --> [].
    digits([D|Ds]) --> digit(D), digits(Ds).
    

    示例查询:

    ?- phrase(digits(Ds), "5235").
    Ds = ['5', '2', '3', '5'] ;
    false.
    

    最后,让我们将所有这些组合成一个整数

    integer(I) --> digit(D), digits(Ds), { number_chars(I, [D|Ds]) }.
    

    使用number_chars/2,我们正在执行字符与实际整数之间的关键转换,您需要在自己的代表中进行转换。

    示例查询:

    ?- phrase(integer(I), "5235").
    I = 5235 ;
    false.
    

    使用这些构建基块,您可以通过其他语法元素方便地描述此类字符列表的一般大纲

    总的来说,您最终的语法可能如下所示:

    pattern --> "(", whitespace, "(", integer, ",", integer, ")", ...
    

    您需要提供whitespace//0的定义并完成整个说明。

    有关此方法的详情,请参阅

答案 1 :(得分:0)

在Prolog中,我们编写谓词,而不是函数,在最基本的情况下,只能限定关系的“真实性” - 通常由谓词的“名称”描述,所谓的仿函数 - 参数之中。

所以,你正在写 3 参数之间的关系:

parse(Needle, Haystack, Found) :-
   ...

你应该写下另一个关系,当Needle匹配Haystack一个元素时,这种关系就成立了。所以你可以选择:递归解析/ 3,其中要匹配的当前元素在头部模式中显式(即parse(Needle, [Element|Haystack], Found) :- etc)或使用库中的member / 2(列表) ), on backtracking 将迭代元素......