我应该如何处理逻辑编程中的重复更新?

时间:2016-10-21 03:19:28

标签: prolog scheme minikanren

特别是我正在尝试确定解决以下类型问题的最佳方法:

我感兴趣的例子是Mitchell机器学习书中的find-s算法,它适用于4个训练样例。

基本思想是针对每个训练样例,x和假设h,通过使其更通用来确定它是否包含x。我需要为训练集中的每个x将h映射到h'。我遇到的问题是如何在逻辑编程语言中最好地解决这个问题。我正在使用minikanren,它大致是在计划中嵌入的prolog。

计算每个h'后,我需要设置!它到全局变量h,然后进入下一个训练示例x。下面的代码是该计划的主要部分。

(define h '(0 0 0 0 0 0))

(define seto
  (lambda (x)
    (project (x)
             (lambda (s) (set! h x) (succeed s)))))

(run* (q)
     (fresh (x h0 h1)
            (trainingo x)
            (== h h0)
            (find-so h0 x h1)
            (seto h1)
            (== h1 q)))

h是全局变量,seto用h1变异h,这是h0和x训练示例中使用find-s算法(find-so)的下一个计算假设。

在prolog中,它(我认为)等同于断言('假设'(H))在每个训练示例X(覆盖前一个)并调用撤回(')之后在应用了所有训练样例后,假设'(H))

我的问题是,这是否是解决这类问题的最佳方法(通过副作用)?

编辑: 我和他的comment一起接受了@mat答案。总之,我需要将训练示例视为列表,并在该列表中使用前向递归,直到我进入空列表。如果我陷入困境,那就是将训练样例作为回溯的一部分,同时找到下一个假设,而不是将它们列入我可以重复使用的列表中直到空。

1 个答案:

答案 0 :(得分:3)

您的建议似乎诱人:使用assertz/0retract/1模拟全局更新。

但是,如果你这样做,有主要缺点

  • 使用全局状态会阻止您使用测试您的谓词隔离
  • 使用破坏性更新会阻止您在更多方向上使用谓词
  • 全局状态的细微和隐含依赖关系使您的谓词中的更改非常容易出错

模拟这些状态变化的声明性解决方案是根据状态之间的关系来思考

例如,当您使用H0计算下一个假设H1时,您可以将其表达为H0和{{1}之间的关系可能还有其他参数。想想谓词如下:

  • H1
  • hypothesis_next(H0, H1)
  • algorithm_hypothesis_next(A, H0, H1)

请注意,此类谓词可以在所有方向读取和 - 理想 - 运行

总的来说,整个解决方案将在您的案例中建模为假设序列

  

parameters_hypothesis_next(Ps, H0, H1)H0H1→...→ H2

有关更多信息和指示,请参阅密切相关的问题:

How to avoid using assert and retractall in Prolog to implement global (or state) variables