gpt4 book ai didi

haskell - 如何说服 ghc 类型级加法是可交换的(实现依赖类型的反向)?

转载 作者:行者123 更新时间:2023-12-05 00:23:44 24 4
gpt4 key购买 nike

这不会编译,因为正如 ghc 告诉我 Add 不是单射的。我如何告诉编译器 Add 确实是可交换的(也许通过告诉它 Add 是单射的)?从 hasochism 论文看来,人们必须以某种方式提供代理。

{-# LANGUAGE DataKinds             #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}

data Nat = Z | S Nat

type family Add a b where
Add Z n = n
Add n Z = n
Add (S n) k = S (Add n k)

data VecList n a where
Nil :: VecList Z a
Cons :: a -> VecList n a -> VecList (S n) a

safeRev :: forall a n . VecList n a -> VecList n a
safeRev xs = safeRevAux Nil xs
where
safeRevAux :: VecList p a -> VecList q a -> VecList (Add p q) a
safeRevAux acc Nil = acc
safeRevAux acc (Cons y ys) = safeRevAux (Cons y acc) ys

一个人可以做到这一点,但感觉在我的口味下隐藏的东西太多了。
{-# LANGUAGE TypeOperators         #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}

import Data.Proxy
import Data.Type.Equality

data Nat = Z | S Nat

type family n1 + n2 where
Z + n2 = n2
(S n1) + n2 = S (n1 + n2)

-- singleton for Nat
data SNat :: Nat -> * where
SZero :: SNat Z
SSucc :: SNat n -> SNat (S n)

-- inductive proof of right-identity of +
plus_id_r :: SNat n -> ((n + Z) :~: n)
plus_id_r SZero = Refl
plus_id_r (SSucc n) = gcastWith (plus_id_r n) Refl

-- inductive proof of simplification on the rhs of +
plus_succ_r :: SNat n1 -> Proxy n2 -> ((n1 + (S n2)) :~: (S (n1 + n2)))
plus_succ_r SZero _ = Refl
plus_succ_r (SSucc n1) proxy_n2 = gcastWith (plus_succ_r n1 proxy_n2) Refl

data VecList n a where
V0 :: VecList Z a
Cons :: a -> VecList n a -> VecList (S n) a

reverseList :: VecList n a -> VecList n a
reverseList V0 = V0
reverseList list = go SZero V0 list
where
go :: SNat n1 -> VecList n1 a-> VecList n2 a -> VecList (n1 + n2) a
go snat acc V0 = gcastWith (plus_id_r snat) acc
go snat acc (Cons h (t :: VecList n3 a)) =
gcastWith (plus_succ_r snat (Proxy :: Proxy n3))
(go (SSucc snat) (Cons h acc) t)

safeHead :: VecList (S n) a -> a
safeHead (Cons x _) = x

test = safeHead $ reverseList (Cons 'a' (Cons 'b' V0))

https://www.haskell.org/pipermail/haskell-cafe/2014-September/115919.html对于最初的想法。

编辑:

@user3237465 这很有趣,而且更多是我想到的
(虽然仔细想想我的问题可能不太好
制定)。

看来我有“公理”
type family n1 :+ n2 where
Z :+ n2 = n2
(S n1) :+ n2 = S (n1 + n2)

因此可以产生像这样的证明
plus_id_r :: SNat n -> ((n + Z) :~: n)
plus_id_r SZero = Refl
plus_id_r (SSucc n) = gcastWith (plus_id_r n) Refl

我觉得这很简洁。我通常会推理这样的事情
  • 在上面的最后一个子句中,我们有 SSucc n::SNat (S k) 所以 n::k
  • 因此我们需要证明 S k + Z :~: S k
  • 由第二个“公理” S k + Z = S (k + Z)
  • 因此我们需要证明 S (k + Z) :~: S k
  • plus_id_rn 给出了 (k + Z) 的“证明”:~: k
  • 和 Refl 给出了一个“证明”,即 m ~ n => S m :~: S n
  • 因此,我们可以使用 gcastWith 统一这些证明以给出所需的
    结果。

  • 对于您的解决方案,您给出“公理”
    type family n :+ m where
    Z :+ m = m
    S n :+ m = n :+ S m

    有了这些, (n + Z) :~: n 的证明就行不通了。
  • 在最后一个子句中,我们再次得到 SSucc x 的类型为 SNat (S k)
  • 因此我们需要证明 S k :+ Z :~: S k
  • 根据第二个新“公理”,我们有 S k + Z = k + S Z
  • 因此我们需要证明 k + S Z :~: S k
  • 所以我们有更复杂的东西需要证明:-(

  • 我可以从新的原始第二个“公理”中证明
    第二个“公理”(所以我的第二个“公理”现在是一个引理?)。
    succ_plus_id :: SNat n1 -> SNat n2 -> (((S n1) :+ n2) :~: (S (n1 :+ n2)))
    succ_plus_id SZero _ = Refl
    succ_plus_id (SSucc n) m = gcastWith (succ_plus_id n (SSucc m)) Refl

    所以现在我应该能够得到原始证明,但我是
    不知道目前如何。

    到目前为止,我的推理是否正确?

    PS:ghc 同意我关于为什么正确身份存在的证明不起作用的推理
    Could not deduce ((n1 :+ 'S 'Z) ~ 'S n1)
    ...
    or from ((n1 :+ 'Z) ~ n1)

    最佳答案

    {-# LANGUAGE GADTs                #-}
    {-# LANGUAGE KindSignatures #-}
    {-# LANGUAGE DataKinds #-}
    {-# LANGUAGE TypeFamilies #-}
    {-# LANGUAGE UndecidableInstances #-}
    {-# LANGUAGE ExplicitForAll #-}

    import Data.Type.Equality

    data Nat = Z | S Nat

    type family (n :: Nat) :+ (m :: Nat) :: Nat where
    Z :+ m = m
    S n :+ m = n :+ S m

    -- Singleton for Nat
    data SNat :: Nat -> * where
    SZero :: SNat Z
    SSucc :: SNat n -> SNat (S n)

    succ_plus_id :: SNat n1 -> SNat n2 -> (((S n1) :+ n2) :~: (S (n1 :+ n2)))
    succ_plus_id SZero _ = Refl
    succ_plus_id (SSucc n) m = gcastWith (succ_plus_id n (SSucc m)) Refl

    plus_id_r :: SNat n -> ((n :+ Z) :~: n)
    plus_id_r SZero = Refl
    plus_id_r (SSucc x) = gcastWith (plus_id_r x) (succ_plus_id x SZero)

    data Vec a n where
    Nil :: Vec a Z
    (:::) :: a -> Vec a n -> Vec a (S n)

    size :: Vec a n -> SNat n
    size Nil = SZero
    size (_ ::: xs) = SSucc $ size xs

    elim0 :: SNat n -> (Vec a (n :+ Z) -> Vec a n)
    elim0 n x = gcastWith (plus_id_r n) x

    accrev :: Vec a n -> Vec a n
    accrev x = elim0 (size x) $ go Nil x where
    go :: Vec a m -> Vec a n -> Vec a (n :+ m)
    go acc Nil = acc
    go acc (x ::: xs) = go (x ::: acc) xs

    safeHead :: Vec a (S n) -> a
    safeHead (x ::: _) = x

    关于haskell - 如何说服 ghc 类型级加法是可交换的(实现依赖类型的反向)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27743472/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com