Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I find the predecessor of a Natural with type-level parity checking?

Tags:

haskell

I've been working with natural numbers with additional type-level parity information. succ has been successfully implemented in the most straightforward way:

succ :: Natural p -> Natural (Opp p)
succ = Succ

However, I'm still struggling with getting pred to typecheck. A minimal example:

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeFamilyDependencies #-}

data Parity = Even | Odd

type family Opp (p :: Parity) = (r :: Parity) | r -> p where
  Opp 'Odd = 'Even
  Opp 'Even = 'Odd

data Natural :: Parity -> * where
  Zero :: Natural 'Even
  Succ :: Natural p -> Natural (Opp p)

pred :: Natural (Opp p) -> Natural p
pred (Succ n) = n

What can I do to successfully implement pred? Right now I'm getting many different large and complicated type errors, especially could not deduce Opp p ~ p1.

like image 950
mitchellvitez Avatar asked Jul 07 '19 16:07

mitchellvitez


People also ask

How is parity check calculated?

Calculating a parity bit, even or odd, is a straightforward thing to do. For odd parity, count the 1s in the message, and if their number is even, add a 1 at a specified position; otherwise, add a 0. For even parity, do the opposite: if the number of 1s is even, add a 0; otherwise, add a 1.

What are the two types of parity check?

In an even parity check, parity bits ensure there are an even number of 1s and 0s in the transmission. In an odd parity check, there are an odd number of 1s and 0s in the transmission.

What is parity how it is used to identify a error What are types of parity with an example?

There are two kinds of parity bits: In even parity, the number of bits with a value of one are counted. If that number is odd, the parity bit value is set to one to make the total number of ones in the set (including the parity bit) an even number.

What is parity check with example?

EXAMPLE. Consider the data unit to be transmitted is 10010001 and even parity is used. On receiving the modified code word, receiver finds the number of 1's is even and even parity is used. So, receiver assumes that no error occurred in the data during transmission though the data is corrupted.


2 Answers

As @chi indicated,

Injectivity annotations are not exploited by GHC for anything except for allowing some types that would be otherwise considered ambiguous. Only for that. They are not used, as one would expect, to infer a ~ b from F a ~ F b. Personally, I consider them to be nearly useless, in their current form.

So you have to define Natural a bit differently:

data Natural :: Parity -> * where
  Zero :: Natural 'Even
  Succ :: (p ~ Opp s, s ~ Opp p) => Natural p -> Natural s

Now you can get both of the things you need.

like image 42
dfeuer Avatar answered Oct 06 '22 02:10

dfeuer


Given singletons for Parity:

data SParity :: Parity -> Type where
  SEven :: SParity Even
  SOdd :: SParity Odd

We can prove the injectivity of Opp

oppInj' :: Opp p ~ Opp q => SParity p -> SParity q -> p :~: q
oppInj' SEven SEven = Refl
oppInj' SOdd SOdd = Refl

Now we can define:

data Natural' :: Parity -> Type where
  Zero' :: Natural' Even
  Succ' :: SParity p -> Natural' p -> Natural' (Opp p)
pred' :: SParity p -> Natural' (Opp p) -> Natural' p
pred' p (Succ' q n) = case oppInj' p q of Refl -> n

You may safely perform erasure to get rid of all the singleton junk:

-- for maximum symmetry, instead of relying on type applications we could
-- just substitute Proxy# in place of SParity everywhere, but meh
oppInj :: forall p q. Opp p ~ Opp q => p :~: q
oppInj = unsafeCoerce Refl -- we know this is OK because oppInj' exists
data Natural :: Parity -> Type where
  Zero :: Natural Even
  Succ :: Natural p -> Natural (Opp p)
pred :: forall p. Natural (Opp p) -> Natural p
pred (Succ (n :: Natural q)) = case oppInj @p @q of Refl -> n

This pattern, doing something with singletons and then erasing them for an improvement in space and time (here it's just a constant factor) is common when doing dependently typed programming in Haskell. Normally, you wouldn't write Natural' or pred', but they are useful as guides for writing the erased versions.

PS: Make sure to handle the Zero case!

like image 57
HTNW Avatar answered Oct 06 '22 02:10

HTNW