证明类型级别分离的幂等性

Rom*_*aka 23 haskell

我已经定义了类型级别的析取如下:

{-# LANGUAGE DataKinds, TypeFamilies #-}

type family Or (a :: Bool) (b :: Bool) :: Bool
type instance Or False a = a
type instance Or True a = True
Run Code Online (Sandbox Code Playgroud)

现在我想(在Haskell中)证明它是幂等的.也就是说,我想idemp用类型构建一个术语

idemp :: a ~ b => proxy (Or a b) -> proxy a
Run Code Online (Sandbox Code Playgroud)

这在操作上等同于id.(显然,我可以定义它,例如unsafeCoerce,但这是作弊.)

可能吗?

pig*_*ker 15

你要求的东西是不可能的,但它可能会做一些非常类似的东西.这是不可能的,因为证明需要对类型级别布尔值进行案例分析,但是您没有数据可以使您发生此类事件.修复方法是通过单例包含此类信息.

首先,请注意您的类型idemp有点混淆.约束a ~ b只是两次命名相同的东西.以下typechecks:

idemq :: p (Or b b) -> p b
idemq = undefined
idemp :: a ~ b => p (Or a b) -> p a
idemp = idemq
Run Code Online (Sandbox Code Playgroud)

(如果你有一个约束a ~ t,其中t不包含a,它通常是很好的替代ta唯一的例外是在.instance声明:一个a在实例头将匹配任何东西,因此,例如将触发即使那件事还没有明显变得t但是我.离题.)

我声称idemq是不可确定的,因为我们没有有用的信息b.唯一可用的数据p,我们不知道是什么p.

我们需要通过案例来推理b.请记住,对于一般的递归类型族,我们可以定义类型级别的布尔值,它们既不是也不TrueFalse.如果我打开UndecidableInstances,我可以定义

type family Loop (b :: Bool) :: Bool
type instance Loop True = Loop False
type instance Loop False = Loop True
Run Code Online (Sandbox Code Playgroud)

所以Loop True不能减少到,True或者False在局部更糟糕的是,没有办法表明这一点

Or (Loop True) (Loop True) ~ Loop True     -- this ain't so
Run Code Online (Sandbox Code Playgroud)

没有办法摆脱它.我们需要运行时证据证明我们b是一个表现良好的布尔人,他们以某种方式计算价值.因此,让我们唱歌

data Booly :: Bool -> * where
  Truey   :: Booly True
  Falsey  :: Booly False
Run Code Online (Sandbox Code Playgroud)

如果我们知道Booly b,我们可以做一个案例分析,告诉我们是什么b.然后每个案例都会很顺利.这是我如何玩它,使用定义的相等类型PolyKinds来收集事实,而不是抽象使用p b.

data (:=:) a b where
  Refl :: a :=: a
Run Code Online (Sandbox Code Playgroud)

我们的关键事实现在已明确陈述并证明:

orIdem :: Booly b -> Or b b :=: b
orIdem Truey   = Refl
orIdem Falsey  = Refl
Run Code Online (Sandbox Code Playgroud)

我们可以通过严格的案例分析来部署这个事实:

idemp :: Booly b -> p (Or b b) -> p b
idemp b p = case orIdem b of Refl -> p
Run Code Online (Sandbox Code Playgroud)

案例分析必须严格,以检查证据不是一些循环的谎言,而是一个诚实的善良Refl默默地收拾只是证明Or b b ~ b需要修复类型.

如果您不想明确地放弃所有这些单例值,您可以像kosmikus建议的那样将它们隐藏在字典中并在需要时提取它们.

Richard Eisenberg和Stephanie Weirich有一个模板Haskell库,可以为您提供这些系列和类.SHE也可以构建它们并让你写

orIdem pi b :: Bool. Or b b :=: b
orIdem {True}   = Refl
orIdem {False}  = Refl
Run Code Online (Sandbox Code Playgroud)

在哪里pi b :: Bool.扩展到forall b :: Bool. Booly b ->.

但它就是这样一个角色.这就是为什么我的团队正在努力pi向Haskell 添加一个实际的东西,它是一个非参数量词(与foralland 不同->),可以通过Haskell类型和术语之间现在非常重要的交集中的东西进行实例化.这pi也可能有一个"隐式"变体,默认情况下参数保持隐藏状态.这两个分别对应于使用单例族和类,但是没有必要将数据类型定义三次以获得额外的工具包.

这可能是值得一提的是,在总共型理论,是不是需要通过布尔的额外副本b在运行时.问题是,b只用来做证明,数据可以被传输p (Or b b)p b,不一定使正在传输的数据.我们不会在运行时根据绑定器进行计算,因此无法编制方程式的不诚实证据,因此我们可以删除证明组件及其副本b.正如兰迪波拉克所说,在强正规化计算中工作的最好方法就是不必对事物进行标准化.

  • 这不是在真空中发生的.如果你要求一个涉及`或bb`的类型并且你为'b`提供两个候选者,则有必要检查它们是否相等.但是,为了预测类型检查的成功或失败,我们已经沦为二次猜测解决策略,这让我很难过. (2认同)

kos*_*kus 7

正如John L在他的评论中所说,据我所知,目前没有办法在没有额外限制的情况下做到这一点.你不能利用的事实,Bool是一个封闭的一种在长期水平,而且也没有办法做案例分析上那种类型的变量Boolidemp.

典型的解决方案是Bool使用单例类型反映术语级别的类型结构:

data SBool :: Bool -> * where
  SFalse :: SBool False
  STrue  :: SBool True
Run Code Online (Sandbox Code Playgroud)

对于任何人来说b :: Bool,只有一个居民SBool b(undefined当然是模数).

有了SBool,这个定理很容易证明(我不知道你为什么要添加额外的等式约束,我要删除它):

idemp' :: SBool a -> proxy (Or a a) -> proxy a
idemp' SFalse x = x
idemp' STrue  x = x
Run Code Online (Sandbox Code Playgroud)

您可以通过定义可以创建SBool表示的类来隐式传递它,而不是显式传递参数:

class CBool (b :: Bool) where
  sBool :: SBool b

instance CBool True  where sBool = STrue
instance CBool False where sBool = SFalse
Run Code Online (Sandbox Code Playgroud)

然后:

idemp :: CBool a => proxy (Or a a) -> proxy a
idemp = idemp' sBool
Run Code Online (Sandbox Code Playgroud)

我不认为你可以摆脱这种CBool约束,但对于任何人来说都是如此a :: Bool,所以这不是一个非常强大的假设.