This does not compile because, as ghc says, adding is not injective. How do you tell the compiler that Add is indeed commutative (maybe by saying that Add is injective)? It seems from the document of Kantochism that you need to somehow provide a proxy.
{-# 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
You can do this, but it seems that too much is happening under the covers for my taste.
{-# 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))
See https://www.haskell.org/pipermail/haskell-cafe/2014-September/115919.html for the original idea.
EDIT:
@ user3237465 This is very interesting and more that I had in mind (although upon reflection my question was probably not well formulated).
I think I have "axioms"
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_r n "", (k + Z): ~: k
- Refl "", m ~ n = > S m: ~: S n
- , , gcast.
.
""
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 :+ 'Z) ~ n1)
...
or from ((n1 :+ 'Z) ~ n1)