Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Model nested data stucture with 'can contain' constraint

Tags:

haskell

Given a set of A, B, C, D... where A contains an ordered list of As, Bs, Cs, ... and Bs have a list of Bs, Cs, Ds... and so on such that any given element can't contain any instances of a 'higher' type how would you model this?

data Hier a = A [a] | B [a] | C [a] | D [a] 

allows this nesting but won't prevent putting a A into a B.

data A = A [ACont]
data B = B [BCont]
data C = C [CCont]
data D = D

data ACont = AA A | AB B | AC C | AD D
data BCont =        BB B | BC C | BD D
data CCont =               CC C | CD D

pattern PatAA x <- AA (A x) where
   PatAA x = AA (A x)

get the nesting right but... yuck. Seven types, a zoo of constructors, no obvious functor instance, and then generically traversing this structure won't be fun. You can reduce the pain a little with some pattern synonyms (one show), but not a heck of a lot.

Is this the best that can be done?

like image 632
Brian Magnuson Avatar asked Dec 04 '25 17:12

Brian Magnuson


1 Answers

(There is an answer to a similar question here)

You can do it with some type-level constraints:

data Nat = Z | S Nat

class (<=) (n :: Nat) (m :: Nat) where isLte :: n <=! m
  
instance Z <= n where isLte = LTEZ
instance n <= m => S n <= S m where isLte = LTES isLte

data (<=!) (n :: Nat) (m :: Nat) where
  LTEZ :: Z <=! n
  LTES :: n <=! m -> S n <=! S m

This code creates a class for (peano) numbers which are less than or equal to each other, and a type representing a proof of that fact.

Here's how you'd use it to make your constructors:

newtype Root (n :: Nat) = Root { getRoot :: [Branch n] }

data Branch (n :: Nat) where
  Branch :: m <= n => Root m -> Branch n
  
type A = Root (S (S (S Z)))
type B = Root (S (S Z))
type C = Root (S Z)
type D = Root Z

a :: [Branch (S (S (S Z)))] -> A
a = Root

b :: [Branch (S (S Z))] -> B
b = Root

c :: [Branch (S Z)] -> C
c = Root

d :: [Branch Z] -> D
d = Root

You can see that this gives you the right constraints, i.e.:

c [Branch (d [])] -- Passes
c [Branch (c [])] -- Passes
c [Branch (b [])] -- Fails typechecker
like image 100
oisdk Avatar answered Dec 06 '25 09:12

oisdk



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!