haskell - 孔类型分辨率不稳定

标签 haskell dependent-type

我最近发现,类型洞与证明上的模式匹配相结合,在 Haskell 中提供了非常好的类似 Agda 的体验。例如:

{-# LANGUAGE
    DataKinds, PolyKinds, TypeFamilies, 
    UndecidableInstances, GADTs, TypeOperators #-}

data (==) :: k -> k -> * where
    Refl :: x == x

sym :: a == b -> b == a
sym Refl = Refl 

data Nat = Zero | Succ Nat

data SNat :: Nat -> * where
    SZero :: SNat Zero
    SSucc :: SNat n -> SNat (Succ n)

type family a + b where
    Zero   + b = b
    Succ a + b = Succ (a + b)

addAssoc :: SNat a -> SNat b -> SNat c -> (a + (b + c)) == ((a + b) + c)
addAssoc SZero b c = Refl
addAssoc (SSucc a) b c = case addAssoc a b c of Refl -> Refl

addComm :: SNat a -> SNat b -> (a + b) == (b + a)
addComm SZero SZero = Refl
addComm (SSucc a) SZero = case addComm a SZero of Refl -> Refl
addComm SZero (SSucc b) = case addComm SZero b of Refl -> Refl
addComm sa@(SSucc a) sb@(SSucc b) =
    case addComm a sb of
        Refl -> case addComm b sa of
            Refl -> case addComm a b of
                Refl -> Refl 

真正好的事情是,我可以用类型孔替换 Refl -> exp 结构的右侧,并且我的孔目标类型会随着证明进行更新,几乎与使用 Agda 中的 rewrite 形式。

但是,有时该漏洞无法更新:

(+.) :: SNat a -> SNat b -> SNat (a + b)
SZero   +. b = b
SSucc a +. b = SSucc (a +. b)
infixl 5 +.

type family a * b where
    Zero   * b = Zero
    Succ a * b = b + (a * b)

(*.) :: SNat a -> SNat b -> SNat (a * b)
SZero   *. b = SZero
SSucc a *. b = b +. (a *. b)
infixl 6 *.

mulDistL :: SNat a -> SNat b -> SNat c -> (a * (b + c)) == ((a * b) + (a * c))
mulDistL SZero b c = Refl
mulDistL (SSucc a) b c = 
    case sym $ addAssoc b (a *. b) (c +. a *. c) of
        -- At this point the target type is
        -- ((b + c) + (n * (b + c))) == (b + ((n * b) + (c + (n * c))))
        -- The next step would be to update the RHS of the equivalence:
        Refl -> case addAssoc (a *. b) c (a *. c) of
            Refl -> _ -- but the type of this hole remains unchanged...

此外,即使目标类型不一定在证明中对齐,如果我从 Agda 粘贴整个内容,它仍然检查得很好:

mulDistL' :: SNat a -> SNat b -> SNat c -> (a * (b + c)) == ((a * b) + (a * c))
mulDistL' SZero b c = Refl
mulDistL' (SSucc a) b c = case
    (sym $ addAssoc b (a *. b) (c +. a *. c),
    addAssoc (a *. b) c (a *. c),
    addComm (a *. b) c,
    sym $ addAssoc c (a *. b) (a *. c),
    addAssoc b c (a *. b +. a *. c),
    mulDistL' a b c
    ) of (Refl, Refl, Refl, Refl, Refl, Refl) -> Refl

您知道为什么会发生这种情况吗(或者我如何以稳健的方式进行证明重写)?

最佳答案

如果您想生成所有可能的此类值,那么您可以编写一个函数来执行此操作,可以使用提供的或指定的边界。

很可能使用类型级别的教堂数字或其他类似的数字来强制创建这些数字,但对于您可能想要/需要的内容来说,这几乎肯定是太多的工作。

这可能不是您想要的(即“除了使用 (x, y),因为 z = 5 - x - y”),但它比尝试对类型级别进行某种强制限制更有意义用于允许有效值。

关于haskell - 孔类型分辨率不稳定,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22082852/

相关文章:

memory-management - 为什么 Haskell 编译器不促进确定性内存管理?

haskell - Aeson 解码结果为“无”

Agda:使用数字解析字符串

coq - Coq/Proof General中类似Agda的编程?

haskell - (>>=) 折叠时的惰性

haskell - 等式推理与喜结连理

haskell - 我的 Pair a a 的类型类

haskell - Haskell 中的单例类型

coq - 如何在 Idris/Agda/Coq 中将类型映射到值?

haskell - 是否可以在 Haskell 中部分应用第 n 个参数?