好的,所以我意识到我可能会在余生中后悔,但...... Djinn实际上是如何工作的?
文档说它使用的算法是“LJ的扩展”,并指出了一篇关于LJT的长篇令人困惑的论文。就我所知,这是一个非常复杂的高度形式化规则系统,用于确定哪些逻辑陈述是真是假。但这甚至没有开始来解释如何将类型签名转换为可执行表达式。据推测,所有复杂的形式推理都是以某种方式涉及,但图片至关重要。
有点像我曾尝试在BASIC中编写Pascal解释器。 (不要笑!我只有十二岁......)我花了好几个小时试图解决它,最后我不得不放弃。我无法弄清楚你是如何从一个包含整个程序的巨型字符串中得到的,以及你可以与已知程序片段进行比较以确定实际操作的内容。
答案当然是你需要写一个叫做“解析器”的东西。一旦你理解了这是什么以及它做了什么,突然间一切都变得明显。哦,编码它仍然不是一件容易的事,但的想法很简单。你只需要编写实际的代码。如果我在十二岁的时候就知道解析器,那么也许我不会花两个小时只是盯着一个空白的屏幕。
我怀疑Djinn正在做的事情从根本上说很简单,但我遗漏了一些重要的细节,这些细节解释了所有这些复杂的逻辑体操如何与Haskell源代码相关...
答案 0 :(得分:32)
Djinn是一个定理证明者。看来你的问题是:定理证明与编程有什么关系?
强类型编程与逻辑关系非常密切。特别是,ML传统中的传统函数语言与Intuitionist Propositional Logic密切相关。
口号是“程序是证明,程序证明的是它的类型。”
一般来说,你可以想到
foo :: Foo
说foo
是公式Foo
的证明。例如类型
a -> b
对应于a
到b
的功能,因此,如果您有a
的证明和a -> b
的证明,则您有b
的证明。因此,功能完全符合逻辑中的含义。类似地
(a,b)
对应于连接(逻辑和)。所以逻辑重言式a -> b -> a & b
对应于Haskell类型a -> b -> (a,b)
并有证据:
\a b -> (a,b)
这是“和介绍规则”
虽然fst :: (a,b) -> a
和snd :: (a,b) -> b
对应于2“和消除规则”
同样,a OR b
对应于Haskell类型Either a b
。
此对应有时在Curry-Howard Correspondence和Haskell 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
表达式将无法帮助您。等等。可用的类型告诉您哪种表达式可能有效。
如果您允许代码调用现有的顶级函数,事情会变得更有趣。除了多态类型的有趣范围问题之外,还有一个问题,即找出哪些函数对您有用或哪些无效。
显然,我将不得不离开并思考一段时间......