2

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

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

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

在计算每个 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 使用 find-s 算法 (find-so) 从 h0 和 x 训练示例中计算的下一个假设 h1 对 h 进行变异。

在序言中,它(我认为)相当于assert('hypothesis'(H))在每个训练示例 X 之后(覆盖前一个)并在所有训练示例之后调用retract('hypothesis'(H))应用。

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

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

4

1 回答 1

3

您的建议可能看起来很诱人assertz/0:使用和模拟全局更新retract/1

但是,如果您这样做,则存在主要缺点:

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

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

例如,当您用于H0计算下一个假设时,您可以将其表示为和 H1之间的关系,可能还有其他参数。想想这样的谓词:H0H1

  • hypothesis_next(H0, H1)
  • algorithm_hypothesis_next(A, H0, H1)
  • parameters_hypothesis_next(Ps, H0, H1)
  • 等等

请注意,这样的谓词可以被读取并且——理想情况下——可以在所有方向上运行!

总的来说,在您的情况下,整个解决方案将被建模为一系列假设

H0H1H2→ … →H

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

如何避免在Prolog中使用assert和retractall来实现全局(或状态)变量

于 2016-10-21T07:15:44.037 回答