如何在Haskell中使用引用来指示类型检查器?

Madgen

在以下程序中填补漏洞是否一定需要非建设性的手段?如果可以,是否x :~: y可以决定?

更一般而言,如何使用引用来指导类型检查器?

(我知道我可以通过定义Choose为GADT来解决此问题,我专门针对类型系列)

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}

module PropositionalDisequality where

import Data.Type.Equality
import Data.Void

type family Choose x y where
  Choose x x = 1
  Choose x _ = 2

lem :: (x :~: y -> Void) -> Choose x y :~: 2
lem refutation = _
Li-yao Xia

如果您尽力实现一个功能,就可以说服自己这是不可能的。如果您不相信,可以将论点变得更正式:我们详尽地列举了程序,发现不可能。事实证明,只有六个有意义的案例需要考虑。

我不知道为什么不经常提出这种说法。

完全不正确的摘要:

  • 第一幕:证明搜索很容易。
  • 第二幕:依赖类型也是如此。
  • 第三幕:Haskell仍然适合编写依赖类型的程序。

一,证明搜索游戏

首先,我们定义搜索空间。

我们可以将任何Haskell定义简化为以下形式之一

lem = (exp)

为了一些表达(exp)现在我们只需要找到一个表达式。

查看在Haskell中进行表达式的所有可能方法:https : //www.haskell.org/onlinereport/haskell2010/haskellch3.html#x8-220003(这并不涉及扩展,请读者练习)。

它可以将页面放在单个列中,因此开始时并没有那么大。而且,它们大多数是用于某种形式的功能应用或模式匹配的糖。我们还可以通过字典传递来对类型类进行除糖处理,因此剩下的是可笑的小lambda演算:

  • lambdas, \x -> ...
  • 模式匹配, case ... of ...
  • 功能应用, f x
  • 构造函数C(包括整数文字)
  • 常量,c(对于无法根据上述结构编写的基元,因此各种内建(seq)以及FFI(如果有的话))
  • 变量(受lambda和case约束)

我们可以排除,每隔一定的理由,我认为真正的问题是关于纯演算(或读者可以枚举常量,排除黑魔术常量一样undefinedunsafeCoerceunsafePerformIO使一切都崩溃(任何类型的居住,对于某些其中,类型系统是不完善的),并留有白色魔术常数,可以通过资金雄厚的论文将当前的理论论点概括为该常数。

我们还可以合理地假设我们想要一个不涉及递归的解决方案(以消除噪声,例如lem = lem和,fix如果您觉得自己以前无法使用它),并且实际上具有正常形式,或者最好是规范形式关于βη-等价形式。换句话说,我们按以下方法改进和检查了可能的解决方案集。

  • lem :: _ -> _具有函数类型,因此我们可以假设WLOG其定义以lambda开头:

    -- Any solution
    lem = (exp)
    
    -- is η-equivalent to a lambda
    lem = \refutation -> (exp) refutation
    
    -- so let's assume we do have a lambda
    lem = \refutation -> _hole
    

现在枚举lambda。

  • 它可能是一个构造函数,然后必须是Refl,但是没有证据表明Choose x y ~ 2在上下文中(这里我们可以形式化和枚举typechecker知道并可以派生的类型相等性,或者进行强制语法(相等性证明)并继续与他们一起玩这个证明搜索游戏),因此不会输入check:

    lem = \refutation -> Refl
    

    也许有某种方式构造该等式证明,但随后该表达式将从其他内容开始,这将是证明的另一种情况。

  • 可能是某个构造函数的应用程序C x1 x2 ...,或者是该变量refutation(是否应用);但是没有一种可能的类型正确,它必须以某种方式产生一个(:~:)Refl这实际上是唯一的方法。

  • 或者可能是一个caseWLOG,case在左边没有嵌套,也没有任何构造函数,因为在两种情况下都可以简化表达式:

    -- Any left-nested case expression
    case (case (e) of { C x1 x2 -> (f) }) { D y1 y2 -> (g) }
    
    -- is equivalent to a right-nested case
    case (e) of { C x1 x2 -> case (f) of { D y1 y2 -> (g) } }
    
    
    
    -- Any case expression with a nested constructor
    case (C u v) of { C x1 x2 -> f x1 x2 }
    
    -- reduces to
    f u v
    

    因此,最后一个子案例是可变案例:

    lem = \refutation -> case refutation (_hole :: x :~: y) of {}
    

    并且我们必须构建一个x :~: y我们列举了_hole再次填充的方法Refl,但没有可用的证据,或者是(跳过某些步骤)case refutation (_anotherHole :: x :~: y) of {},并且手上有无限的下降,这也是荒谬的。这里一个不同的可能论点是,我们可以case从应用程序中取出,以将这种情况从考虑的WLOG中删除。

    -- Any application to a case
    f (case e of C x1 x2 -> g x1 x2)
    
    -- is equivalent to a case with the application inside
    case e of C x1 x2 -> f (g x1 x2)
    

没有更多的情况了。搜索已完成,我们没有找到实现(x :~: y -> Void) -> Choose x y :~: 2QED。

要阅读有关此主题的更多信息,我想一本有关lambda演算的课程/书,直到简单类型的lambda演算的归一化证明应为您提供入门的基本工具。以下论文在第一部分中对此主题进行了介绍,但我承认我对此类材料的难易程度判断不佳:哪些类型的居民独特?Gabriel Scherer着重于纯程序等效

随意提出更多充足的资源和文献资料。


二。修正命题并用依赖类型证明

您最初的直觉认为这应该编码一个有效的命题,这绝对是正确的。我们如何解决它以使其可证明?

从技术上讲,我们要查看的类型可以通过以下方式量化forall

forall x y. (x :~: y -> Void) -> Choose x y :~: 2

的重要特征forall是它是不相关的量词。它引入的变量不能在这种类型的术语中“直接”使用尽管在依赖类型的存在下,这一方面变得更加突出,但它仍然在Haskell至今仍然存在,这为Haskell中的这一点(以及许多其他示例)为何不可“证明”提供了另一种直觉:如果您思考为什么认为该命题是有效的,您自然会从关于是否x等于的案例拆分开始y,但即使要进行案例拆分,您也需要一种方法来确定您所处的一方,当然必须考虑xy,所以它们不能不相关的。forall 在Haskell中,一点也不像大多数人所说的“为所有人”所指。

关于相关性的一些讨论可以在Richard Eisenberg的论文《Haskell的依存类型》中找到(特别是第3.1.1.5节是一个示例,第4.3节是从属Haskell的相关性,第8.7节是与其他语言的对比)。依赖类型)。

依赖的Haskell将需要一个相关的量词来补充forall,这将使我们更接近证明这一点:

foreach x y. (x :~: y -> Void) -> Choose x y :~: 2

然后我们可能会这样写:

lem :: foreach x y. (x :~: y -> Void) -> Choose x y :~: 2
lem x y p = case x ==? u of
  Left r -> absurd (p r)  -- x ~ y, that's absurd!
  Right Irrefl -> Refl    -- x /~ y, so Choose x y = 2

这还假定了不等式的第一概念/~,即补充~,以帮助Choose减少在上下文中的不平等和决策功能(==?) :: foreach x y. Either (x :~: y) (x :/~: y)实际上,这种机器不是必需的,只是可以简化答案。

在这一点上,我正在编造东西,因为尚不存在从属Haskell,但这在相关的从属类型语言(Coq,Agda,Idris,Lean)中很容易实现,对类型族进行了适当的替换Choose(类型族在有些功能太强大而无法翻译为单纯的功能,因此可能会作弊,但我离题了。

这是Coq中的一个可比较程序,它还显示了lem适用于1和2的程序,并且适当的证明确实会因的反射率而减少为证明choose 1 2 = 2

https://gist.github.com/Lysxia/5a9b6996a3aae741688e7bf83903887b


三,没有依赖类型

困难的一个关键来源是Choose实例重叠的封闭型族。这是有问题的,因为在Haskell中没有适当的方式来表达xy不相等这一事实,要知道第一个子句Choose x x不适用。

如果您喜欢伪依赖的Haskell,更有效的方法是使用布尔类型相等:

-- In the base library
import Data.Type.Bool (If)
import Data.Type.Equality (type (==))

type Choose x y = If (x == y) 1 2

等式约束的替代编码对于此样式很有用:

type x ~~ y = ((x == y) ~ 'True)
type x /~ y = ((x == y) ~ 'False)

这样,我们就可以得到上述类型命题的另一个版本,可以在当前的Haskell中表达(其中SBool的单例类型Bool),从本质上可以理解为添加了x等于相等的假设y这与先前关于“无关紧要”的主张并不矛盾forall,该函数正在检查布尔值(或更确切地说是SBool),该布尔值将检查x延迟y给调用者lem

lem :: forall x y. SBool (x == y) -> ((x ~~ y) => Void) -> Choose x y :~: 2
lem decideEq p = case decideEq of
  STrue -> absurd p
  SFalse -> Refl

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

如何在firestore中使用引用类型?

来自分类Dev

如何在Reactive Spring Data中使用其他对象的引用来获取对象?

来自分类Dev

如何在 Java 中使用来自另一个包的 OSGI 引用

来自分类Dev

在Haskell中使用RankNTypes进行类型检查

来自分类Dev

如何在PHP中使用类型检查执行> =

来自分类Dev

在显示活动之前,如何在android中使用来自广播接收器的数据

来自分类Dev

如何在app.post函数中使用来自外部服务器的值

来自分类Dev

在显示活动之前,如何在android中使用来自广播接收器的数据

来自分类Dev

如何在HTML中使用来自控制器的角度变量?

来自分类Dev

如何在Haskell中使用(。)

来自分类Dev

如何在Haskell中使用(。)

来自分类Dev

如何在Pinescript的安全功能(多TF指示器)中使用输入?

来自分类Dev

如何在Android中使用水平的“物料进度指示器”?

来自分类Dev

如何在Unity中使自定义检查器添加对象引用

来自分类Dev

如何在Haskell中使用其他类型以提高类型安全性

来自分类Dev

如何在ngif中使用来自ngfor的变量?

来自分类Dev

如何在 ruby 中使用来自 yaml 的登录凭据

来自分类Dev

R Shiny:如何在服务器部分中使用来自ui的UI文本输入来设置数据帧?

来自分类Dev

如何在 swift 中使用/引用自定义类型的字典中的键?

来自分类Dev

如何在Haskell数据类型中使用整数文字和算术

来自分类Dev

如何在Haskell中使用记录语法为类型定义`bind`?

来自分类Dev

如何在Haskell中使用不同类型monad的值

来自分类Dev

如何在Haskell / Aeson中使用类型函数解析多态值?

来自分类Dev

如何在Haskell中使用HUnit测试我自己的数据类型?

来自分类Dev

如何在循环引用中使用@JsonIdentityInfo?

来自分类Dev

如何在变量引用中使用管道?

来自分类Dev

如何在clang中使用__weak引用?

来自分类Dev

如何在WPF中的图像透明区域中使用图像和进度指示器中的ProgressBar边框

来自分类Dev

如何在Haskell中使用$避免括号

Related 相关文章

  1. 1

    如何在firestore中使用引用类型?

  2. 2

    如何在Reactive Spring Data中使用其他对象的引用来获取对象?

  3. 3

    如何在 Java 中使用来自另一个包的 OSGI 引用

  4. 4

    在Haskell中使用RankNTypes进行类型检查

  5. 5

    如何在PHP中使用类型检查执行> =

  6. 6

    在显示活动之前,如何在android中使用来自广播接收器的数据

  7. 7

    如何在app.post函数中使用来自外部服务器的值

  8. 8

    在显示活动之前,如何在android中使用来自广播接收器的数据

  9. 9

    如何在HTML中使用来自控制器的角度变量?

  10. 10

    如何在Haskell中使用(。)

  11. 11

    如何在Haskell中使用(。)

  12. 12

    如何在Pinescript的安全功能(多TF指示器)中使用输入?

  13. 13

    如何在Android中使用水平的“物料进度指示器”?

  14. 14

    如何在Unity中使自定义检查器添加对象引用

  15. 15

    如何在Haskell中使用其他类型以提高类型安全性

  16. 16

    如何在ngif中使用来自ngfor的变量?

  17. 17

    如何在 ruby 中使用来自 yaml 的登录凭据

  18. 18

    R Shiny:如何在服务器部分中使用来自ui的UI文本输入来设置数据帧?

  19. 19

    如何在 swift 中使用/引用自定义类型的字典中的键?

  20. 20

    如何在Haskell数据类型中使用整数文字和算术

  21. 21

    如何在Haskell中使用记录语法为类型定义`bind`?

  22. 22

    如何在Haskell中使用不同类型monad的值

  23. 23

    如何在Haskell / Aeson中使用类型函数解析多态值?

  24. 24

    如何在Haskell中使用HUnit测试我自己的数据类型?

  25. 25

    如何在循环引用中使用@JsonIdentityInfo?

  26. 26

    如何在变量引用中使用管道?

  27. 27

    如何在clang中使用__weak引用?

  28. 28

    如何在WPF中的图像透明区域中使用图像和进度指示器中的ProgressBar边框

  29. 29

    如何在Haskell中使用$避免括号

热门标签

归档