我怎样才能使用矛盾的证据呢?

时间:2016-04-17 18:56:36

标签: haskell types typeclass

在编写about how to do subtyping in Haskell时,我想到能够“使用”诸如True ~ False之类的矛盾证据来告知编译器死分支是非常方便的。使用另一个标准空类型VoidEmptyCase扩展名允许您以这种方式标记死分支(即包含类型Void的值):

use :: Void -> a
use x = case x of

我想为不可满足的Constraint做类似的事情。

是否有一个术语可以赋予True ~ False => a类型但不能给出类型a

2 个答案:

答案 0 :(得分:8)

您通常可以通过将证据的确切性质与您计划使用它的方式分开来实现。如果类型检查器看到你引入了一个荒谬的约束,它就会咆哮你。因此,诀窍是将这种平等推迟到:~:之后,然后使用通常合理的函数来操纵平等证据。

{-# LANGUAGE GADTs, TypeOperators, ScopedTypeVariables, DataKinds,
      PolyKinds, RankNTypes #-}
{-# OPTIONS_GHC -Wall #-}

module TrueFalse where
import Data.Type.Equality

data Foo (a :: Bool) where
  Can :: Foo 'False
  Can't :: (forall x . x) -> Foo 'True

extr :: Foo 'True -> a
extr (Can't x) = x

subst :: a :~: b -> f a -> f b
subst Refl x = x

whoop :: 'False :~: 'True -> a
whoop pf = extr $ subst pf Can

whoop函数似乎与您正在寻找的大致相同。

正如AndrásKovács评论的那样,您甚至可以在EmptyCase值上使用'False :~: 'True。不幸的是,目前(7.10.3)EmptyCase doesn't warn about non-exhaustive matches。希望很快就能修复。

答案 1 :(得分:4)

如果这种约束作为给定约束出现,则会导致类型错误。一般来说,这适用于typechecker认为不可能的任何约束。

甚至编写功能

f :: ('True ~ 'False) => x
f = undefined 

没有类型检查,因为函数的上下文是函数体中的给定约束 - 而'True ~ 'False根本不能作为给定的约束出现。

充其量你可以有例如

import Data.Type.Equality ((:~:)(..))

type family (==) (a :: k) (b :: k) :: Bool where 
  a == a = 'True 
  a == b = 'False 

f :: ((x == y) ~ 'False) => x :~: y -> a
-- f Refl = undefined -- Inaccessible code 
f = \case{} 

再次回到EmptyCase,这次是:~:。注意

f :: ((x == y) ~ 'False, x ~ y) => a 

也会减少到一个非常不可能的约束,因为x == x会减少到True。你可以编写一个等级谓词,它不会减少平凡的相等类型(例如Data.Type.Equality中的那个),它允许你写:

import Data.Type.Equality 

f :: ((x == y) ~ 'False, x ~ y) => Proxy '(x,y) -> a 
f = undefined 

可能有一种方法可以在不使用undefined的情况下编写此函数,但无论如何它都是没有意义的,因为GHC会立即减少此类型:

>:t f
f :: forall (k :: BOX) (y :: k) a. ((y == y) ~ 'False) => Proxy '(y, y) -> a

即使没有约束,在定义上也不可能用两种不同类型调用函数Proxy '(y,y) -> a。无法从类型检查器中隐藏等式约束~ - 您必须使用不同的同等形式,一种不会减少到~的等式。