【问题标题】:Prolog List Manipulation AssistanceProlog 列表操作协助
【发布时间】:2017-05-05 14:50:35
【问题描述】:

我有一个 prolog 作业问题,我一直在努力解决这个问题。基本问题是我有三个列表,每个列表都有包含一个短语和一个值的成员。我应该随机选择列表中的一个成员,打印短语,然后重复,直到我从至少两个列表中打印出短语,并且打印的短语的总值至少为 9。

到目前为止我所做的:我已经完成了程序的几十次迭代,并搜索了 SWI 文档以及 Lean Prolog Now 和堆栈溢出。在此过程中,我了解到使用 assert() 将项目添加到列表会导致后续运行损坏,所有变量都是本地的,将单个项目附加到空列表不会导致列表但确实会导致在有趣的错误消息中,下一次递归,并且你不能改变变量的值。 我的程序成功地执行了以下操作:随机选择 3 个列表之一。从该列表中随机抓取一个项目。将所选项目中的短语和值放入不同的变量中,并打印出来。

它的主要问题是我的列表操作似乎不起作用。 “append(Usedlist, Z, Usedlist3)”行在代码的第二次迭代中总是失败而不会引发错误。此外,我认为 member(Z, Usedlist) 不能正常工作,因为我在第二次迭代中随机重复它不能正常工作。但是,我怀疑错误在于未正确添加到列表中。

相关代码(出于理智原因,精简为 1 个列表)

main :-
      A is 0,
      B is 0,
      C is 0,
      Num is 0,
      Usedlist = ["Garbage data1", "More garbage data"],
      prologwhile(Num, A, B, C, Usedlist).

    prologwhile(Num, A, B, C, Usedlist) :- Num < 9 ,
    F = [["time of day", 1], ["Season", 5], ["Yesterdays weather", 2], ["Month of last big storm", 2], ["Randomly generated riddle", 9], ["A captcha", 1], ['Current day', 6], ["Tomorrows date", 5]],

    random_member(Rand, F),
    nth0(1, Rand, Add),
    writeln(Rand),  
    nth0(0, Rand, Z),
    writeln(Usedlist),
    (   member(Z, Usedlist) ->
        writeln("Test5"),
        prologwhile(Num, A, B, C, Usedlist)
    ;   writeln(Rand),
        writeln(Add),
        writeln("Test6"),
        append(Usedlist, Z, Usedlist3),
        writeln(Z),
        C3 is 1,
        Num3 is Num + Add,
        writeln(Num3),
        prologwhile(Num3, A, B, C3, Usedlist3)
    )

样本输出

[Tomorrows date,5]
[Garbage data1,More garbage data]
[Tomorrows date,5]
5
Test6
Tomorrows date
5
[time of day,1]
[Garbage data1,More garbage data|Tomorrows date]
[time of day,1]
1
Test6
false.

【问题讨论】:

    标签: list prolog


    【解决方案1】:

    让我们分阶段解决它:

    1。消除副作用,简化程序

    我从您的程序的以下直接更改开始:

    1. 消除所有执行 I/O 的目标,因为这些目标只会妨碍我们想对程序执行的推理。
    2. 而不是X is C 其中C 是一个常量,并且该变量仅在代码的其余部分中使用一次,我只是使用常量@ 987654323@直接

    因此,我们得到:

    主要的 :- prologwhile(0, 0, 0, 0, ["垃圾数据1", "更多垃圾数据"])。 prologwhile(Num, A, B, C, Usedlist) :- 数字 prologwhile(Num, A, B, C, Usedlist) ;附加(Usedlist,Z,Usedlist3), Num3 是 Num + Add, prologwhile(Num3, A, B, 1, Usedlist3) )。

    现在,为了便于阅读,我进行了以下附加更改:

    • 我将短语分解为它们自己的谓词
    • 我使用pairs而不是列表来表示Phrase-Valuepairs
    • 我使用 pattern 匹配和更具说服力的变量名称。

    总的来说,我们现在有:

    主要的 :- prologwhile(0, 0, 0, 0, ["垃圾数据1", "更多垃圾数据"])。 prologwhile(Num, A, B, C, Usedlist) :- 数字 prologwhile(Num, A, B, C, Usedlist) ;附加(Usedlist,短语,Usedlist3), Num3 是 Num + 值, prologwhile(Num3, A, B, 1, Usedlist3) )。 短语([“一天中的时间”-1, “季节”-5, “昨天的天气”-2, “上次大风暴的月份”-2, “随机产生的谜语”-9, “验证码”-1, '当天'-6, “明天日期”-5])。

    从今以后,我假设phrases/1在上面的sn-p中定义,并且不携带它的定义。

    2。查找故障原因

    现在开始关于程序的实际推理,因为我们有:

    ?- 主要的。 错误。

    为了帮助你找到错误,我在程序中添加了以下定义:

    $(目标):- 描绘子句(目标), 目标。

    我们可以在prologwhile/5中使用这个谓词如下:

    prologwhile(Num, A, B, C, Usedlist) :- 数字 prologwhile(Num, A, B, C, Usedlist) ; $(append(Usedlist, Phrase, Usedlist3)), Num3 是 Num + 值, prologwhile(Num3, A, B, 1, Usedlist3) )。

    我们现在得到:

    ?- 主要的。 append(["垃圾数据1", "更多垃圾数据"], "验证码", _). append(["垃圾数据1", "更多垃圾数据"|"验证码"], '当前日期', _)。 错误的。

    那么问题来了:

    ?- append(["垃圾数据1", "更多垃圾数据"|"验证码"], '当前日期', _)。

    这个目标失败因此整个程序失败了。

    你显然打算如下:

    append(Usedlist, [Phrase], Usedlist3)

    也就是说,你想附加两个 lists 的内容,而不是一个 list 和一些 else 的内容。请注意,在列表前面预先添加元素而不是附加它们通常是一个好主意以获得良好的性能,因此我们可以这样写:

    Usedlist3 = [短语|Usedlist]

    所以,整个谓词变成:

    prologwhile(Num, A, B, C, Usedlist) :- 数字 prologwhile(Num, A, B, C, Usedlist) ; Usedlist3 = [短语|Usedlist], Num3 是 Num + 值, prologwhile(Num3, A, B, 1, Usedlist3) )。

    或更短:

    prologwhile(Num, A, B, C, Usedlist) :- 数字 prologwhile(Num, A, B, C, Usedlist) ; Num3 是 Num + 值, prologwhile(Num3, A, B, 1, [Phrase|Usedlist]) )。

    但是,我们仍然有:

    ?- 主要的。 错误。

    要了解为什么这个仍然会失败,请考虑谓词应该成立的情况。经过一番思考,以下是它应该成立的情况:

    prologwhile(Num, _, _, _, [_,_|_]) :- Num >= 9。

    因此,我们将案例添加到我们的程序中,获得:

    prologwhile(Num, _, _, _, [_,_|_]) :- Num >= 9. prologwhile(Num, A, B, C, Usedlist) :- 数字 prologwhile(Num, A, B, C, Usedlist) ; Num3 是 Num + 值, prologwhile(Num3, A, B, 1, [Phrase|Usedlist]) )。

    请注意我是如何在累积列表上使用模式匹配来检测使用来自至少 2 个不同对的元素的情况。

    现在,我们终于有了:

    ?- 主要的。 真的。

    这很酷,但 没用。

    3。在顶层报告实际解决方案

    现在,是时候就该计划提出一些更深入的问题了。例如,所有这些论点到底在做什么?让我们简单地忘记ABC,获得:

    主要的 :- prologwhile(0, ["垃圾数据1", "更多垃圾数据"])。 prologwhile(Num, [_,_|_]) :- Num >= 9。 prologwhile(Num, Usedlist) :- 数字 prologwhile(Num, Usedlist) ; Num3 是 Num + 值, prologwhile(Num3, [Phrase|Usedlist]) )。

    同样有效:

    ?- 主要的。 真的。

    另一方面,似乎缺少了一件重要的事情,即我们实际使用过的短语!让我们通过引入一个代表它们的参数来获得它们。在这种情况下,一个有用的命名约定是一对 Ls0LsLs0 表示 initial 列表,Ls 最后一个我们想要 toplevel 报告。

    我们也可以简单地忘记“垃圾”元素。

    这样整个程序就变成了:

    解决方案(列表): - 序言(0,[],列表)。 prologwhile(Num, Ls, Ls) :- Num >= 9, Ls = [_,_|_]。 prologwhile(Num, Ls0, Ls) :- 数字 prologwhile(Num, Ls0, Ls) ; Num3 是 Num + 值, prologwhile(Num3, [Phrase|Ls0], Ls) )。 短语([“一天中的时间”-1, “季节”-5, “昨天的天气”-2, “上次大风暴的月份”-2, “随机产生的谜语”-9, “验证码”-1, '当天'-6, “明天日期”-5])。

    示例查询:

    ?- 解决方案(Ls)。 Ls = ["随机生成的谜语", "Season"] ; 错误的。

    您还可以轻松地扩展它以报告总价值,无论是在构建列表时还是在一个简单的附加步骤中。我把它留作练习。另请注意,prologwhileisnotaseasytoread 例如using_underscores_would_be

    【讨论】:

    • @mat:非常好的指导性答案,+s(0)!
    • 因为我一直在做更多的工作,你能向我解释一下最后两个步骤是如何工作的吗?我需要重新添加 A、B 和 C,但我不能没有整个事情失败。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多