What is Haskell missing for totality checking?
全(功能)语言是一种所有内容都可以显示为终止的语言。显然,有很多地方我不想这样做——抛出异常有时很方便,Web服务器不应该终止等等。但有时,我希望进行局部总体检查以启用某些优化。例如,如果我有一个可证明的全函数
1 2
| commutativity :: forall (n :: Nat) (m :: Nat). n + m :~: m + n
commutativity = ... |
然后,由于:~:只有一个居民(Refl),GHC可以优化
1 2 3
| gcastWith (commutativity @n @m) someExpression
==>
someExpression |
号
我对交换性的证明是,从O(n)运行时成本到免费。所以,现在我的问题是:
在为哈斯凯尔做一个全面检查时,有哪些微妙的困难?
显然,这样的检查程序是保守的,所以当GHC不确定某个东西是完全的(或者懒得检查)时,它可能会认为它不是……在我看来,拼凑出一个不那么聪明,但仍然非常有用的检查程序也许并不难(至少消除我所有的算术证明应该很简单)。然而,我似乎找不到任何努力把这样一个东西建设成温室气体,所以很明显我错过了一些相当大的限制。继续吧,粉碎我的梦想。:)
相关但不是最近的:Neil Mitchell的《永不动摇的哈斯克尔》,2005年。
- "由于:~:只有一个居民(Refl),GHC可以优化gcastWith commutativity e ? e"—首先,我认为GHC在某些情况下已经这样做了(如果它专门针对具体的n和m?-不过,一般来说,我怀疑这种整体性分析确实有助于提高性能,因为依赖类型证明的能力实际上是它们的构造性,而构造等式等方面的工作通常在运行时是不可能的。
- @我认为GHC可以对具体的n和m进行优化,但这似乎有点脆弱。我认为我的大多数(当前)证明用例都是O(1)可优化的…您是否有一个依赖类型证明的示例,通常不能是O(1)?我不怀疑它们的存在-我只想举个例子来思考。谢谢!
- @左撇子关于:关于。建设性:不完全是;你混淆了"建设性证据"和"计算性内容"。由于a :~: b只有一个非居民,如果我们在一个整体环境中,我们可以说a :~: b的证明没有计算内容;我们知道castWith :: (a :~: b) -> a -> b必须在计算上等价于const id(给定总量)。在同伦类型的理论设置中,等式确实有计算内容,所以你必须做这项工作——但是在这个设置中,Refl并不是a = b的唯一居民!
- Web服务器不应该终止。此外,它应该做出反应,(也就是说,"生产力")是与生产有关的整体性形式。你不能写一个完整的服务器的神话是保留一般递归的一个较差的借口。我同意haskell的完整片段是有价值的(我曾经称之为"ask",因为你可以自信地,因为它是haskell的一部分,而不是"地狱")。证明擦除动机(CFCOQ提取)良好。将数据与codata(haskell中比较棘手)区分开来会有很大帮助。
- @左顾右盼,正如Antal上面提到的,可以为单个非底值类型(如a:~:b类型)构建优化的O(1)证明。每次有e :: a:~:b和终端检查程序时,都确保e是非底部的,一旦可以使用unsafeCoerce Refl对其进行优化。棘手的部分是证明了haskell codata的整体性,因为诱导是不够的。也许我们可以将其限制为"数据"——仅限于类型/种类,如data Nat = O | S !Nat,其中归纳法可以是声音。不过,我对此并不十分自信。
- @我认为,亚历克对Either (n :~: m) ((n :~: m) -> Void)的证明(对peano naturals n,m的证明)不能是o(1)。在运行时,我们需要检查运行时值是否相等。对于单值类型,我想应该总是O(1)。
- @当然!我只考虑单值类型,如:~:或()。否则,我同意所有的赌注都取消了(我认为在这里可以用改进类型来解决问题,但这有点超出范围,而且在GHC的视线范围内是看不到的)。
- 由于:~:是盒装的,它有两个居民:Refl和_|_。
- @Heimdell这就是这个问题的关键所在——如果生成:~:的函数为total,则不能是_|_。
- @亚历克,如果你想在哈斯克尔买点东西,那就应该开箱。而且Ypu会对未装箱的东西产生问题,因为它们与装箱的不同。
Liquid Haskell进行总量检查:https://github.com/ucsd progsys/liquid haskell终端检查
。
By default a termination check is performed on all recursive functions.
Use the no-termination option to disable the check
liquid --no-termination test.hs
In recursive functions the first algebraic or integer argument should be decreasing.
The default decreasing measure for lists is length and Integers its value.
号
(我为子孙后代提供了截图和引用。)
与使用agda或其他语言进行整体性检查类似,函数的参数在结构上必须随时间变小才能达到基本情况。与总量检查相结合,可以对许多函数进行可靠的检查。lh还支持通过指示减少的方式来帮助检查器,您可以使用不透明的抽象数据类型或来自ffi的抽象数据类型。这真的很实用。
- 作为GHC的一部分,有什么限制?据了解,lh只是一种高级过梁——它不会优化只有一个居民的类型的总价值。谢谢!
- @Richard A.Eisenberg的论文arxiv.org/abs/1610.07978的ALEC第8.4节对如何将类似Liquid Haskell的内容合并到未来依赖类型的Haskell中提出了一些建议。
- @丹尼亚兹,有趣的是,你提出这个问题:那个部分实际上是我问这个问题的原因之一。我正试图找出到底是什么工作,将进入这样一个GHC插件。我希望能有更多关于数据/密码数据细节的讨论(以及在这两种数据之间的讨厌的讨论)。