Djinn是如何工作的?

时间:2012-04-18 21:01:10

标签: haskell types logic

好的,所以我意识到我可能会在余生中后悔,但...... Djinn实际上是如何工作的?

文档说它使用的算法是“LJ的扩展”,并指出了一篇关于LJT的长篇令人困惑的论文。就我所知,这是一个非常复杂的高度形式化规则系统,用于确定哪些逻辑陈述是真是假。但这甚至没有开始来解释如何将类型签名转换为可执行表达式。据推测,所有复杂的形式推理都是以某种方式涉及,但图片至关重要。


有点像我曾尝试在BASIC中编写Pascal解释器。 (不要笑!我只有十二岁......)我花了好几个小时试图解决它,最后我不得不放弃。我无法弄清楚你是如何从一个包含整个程序的巨型字符串中得到的,以及你可以与已知程序片段进行比较以确定实际操作的内容。

答案当然是你需要写一个叫做“解析器”的东西。一旦你理解了这是什么以及它做了什么,突然间一切都变得明显。哦,编码它仍然不是一件容易的事,但的想法很简单。你只需要编写实际的代码。如果我在十二岁的时候就知道解析器,那么也许我不会花两个小时只是盯着一个空白的屏幕。

我怀疑Djinn正在做的事情从根本上说很简单,但我遗漏了一些重要的细节,这些细节解释了所有这些复杂的逻辑体操如何与Haskell源代码相关...

3 个答案:

答案 0 :(得分:32)

Djinn是一个定理证明者。看来你的问题是:定理证明与编程有什么关系?

强类型编程与逻辑关系非常密切。特别是,ML传统中的传统函数语言与Intuitionist Propositional Logic密切相关。

口号是“程序是证明,程序证明的是它的类型。”
一般来说,你可以想到

 foo :: Foo

foo是公式Foo的证明。例如类型

 a -> b  

对应于ab的功能,因此,如果您有a的证明和a -> b的证明,则您有b的证明。因此,功能完全符合逻辑中的含义。类似地

(a,b)

对应于连接(逻辑和)。所以逻辑重言式a -> b -> a & b对应于Haskell类型a -> b -> (a,b) 并有证据:

\a b -> (a,b)

这是“和介绍规则” 虽然fst :: (a,b) -> asnd :: (a,b) -> b对应于2“和消除规则”

同样,a OR b对应于Haskell类型Either a b

此对应有时在Curry-Howard CorrespondenceHaskell Curry之后被称为“Curry-Howard Isomorphism”或“William Alvin Howard

这个故事因Haskell中的非整体而变得复杂。

Djinn“只是”一个定理证明者。

如果您有兴趣尝试编写克隆,那么“简单定理证明者”的谷歌搜索结果的第一页有this论文,其中描述了为LK编写似乎用SML编写的定理证明器。

编辑: 关于“定理如何证明可行?”答案是,在某种意义上说并不难。这只是一个搜索问题:

考虑重述的问题:我们有一套命题,我们知道如何证明S,以及我们想要证明的命题P.我们该怎么办? 首先,我们问:我们是否已经在S中证明了P?如果是这样,我们可以使用它,如果不是,我们可以在P

模式匹配
case P of
   (a -> b) -> add a to S, and prove b (-> introduction)
   (a ^ b)  -> prove a, then prove b (and introduction)
   (a v b)  -> try to prove a, if that doesn't work prove b (or introduction)

如果没有这些工作

for each conjunction `a ^ b` in S, add a and b to S (and elimination)
for each disjunction `a v b` in S, try proving `(a -> P) ^ (b -> P)` (or elimination)
for each implication `a -> P` is S, try proving `a` (-> elimination)

真正的定理证明有一些聪明,但想法是一样的。 “决策程序”的研究领域探讨了为某些保证有效的公式找到证据的策略。另一方面,“战术”着眼于如何优化订购证明搜索。

至于:“如何将证据翻译成Haskell?”

正式系统中的每个推理规则对应于一些简单的Haskell构造,因此如果你有一个推理规则树,你可以构造一个相应的程序 - 毕竟Haskell是一种证明语言。

含义介绍:

\s -> ?

或介绍

Left
Right

和介绍

\a b -> (a,b)

消除

fst
snd

奥古斯丁在他的回答中说,他们在Djinn实施这一点的方式对于SO答案来说有点单调乏味。我敢打赌,你可以自己想一想如何实现它。

答案 1 :(得分:22)

一般来说,根据库里 - 霍华德的同构,类型和命题之间存在对应关系,也存在价值和证据。 Djinn使用这封信。

更具体一点,比如你想要找到(a, b) -> (b, a)类型的Haskell术语。首先,您将类型转换为逻辑中的语句(Djinn使用命题逻辑,即没有量词)。逻辑陈述为(A and B) is true implies (B and A) is true。下一步是证明这一点。对于命题逻辑,总是可以机械地证明或反驳陈述。如果我们可以反驳它,那么这意味着在(终止)Haskell中不会有相应的术语。如果我们可以证明它,那么就有一个类型的Haskell术语,而且,Haskell术语与证明具有完全相同的结构。

最后一个声明必须是合格的。您可以选择使用不同的公理和推理规则来证明该陈述。如果你选择一个建设性的逻辑,证明和Haskell术语之间只有一个对应关系。 “正常”,即经典逻辑具有像A or (not A)这样的公理。这将对应于Haskell类型Either a (a -> Void),但是没有这种类型的Haskell术语,所以我们不能使用经典逻辑。 任何命题陈述都可以在建设性的命题逻辑中被证明​​或证明是正确的,但是这样做比在经典逻辑中要多得多。

所以回顾一下,Djinn通过将类型转换为逻辑中的命题来工作,然后它使用建构逻辑的决策过程来证明命题(如果可能的话),最后证明被转换回Haskell术语。 / p>

(在这里说明这是如何工作太痛苦了,但是在白板上给我10分钟,对你来说一点都很清楚。)

作为最后评论供您思考:如果您拥有Scheme Either a (a -> Void),则可以实施call/cc。选择一个更具体的类型,如Either a (a -> Int),并弄清楚如何。

答案 2 :(得分:3)

也许我看着这一切都错了。也许所有这些形式逻辑的东西只是一种分心。不是盯着LJT或其他什么的演绎规则,也许我应该做的事情就是看Haskell。

Haskell中有6种可能的表达形式?每个人对它使用的变量都有不同的类型限制,对吧?所以,也许我只是为函数类型中的每个参数生成一个新变量,并开始查看我可以构造的表达式。

甚至不需要在强力搜索中生成所有可能的表达式。如果你的参数都没有函数类型,那么尝试函数应用程序是没有意义的。如果您的所有参数都是多态类型变量,case表达式将无法帮助您。等等。可用的类型告诉您哪种表达式可能有效。

如果您允许代码调用现有的顶级函数,事情会变得更有趣。除了多态类型的有趣范围问题之外,还有一个问题,即找出哪些函数对您有用或哪些无效。

显然,我将不得不离开并思考一段时间......