haskell - Type-level restriction on "mixed" arrays, while allowing arrays of arrays with different content in the inner arrays -



haskell - Type-level restriction on "mixed" arrays, while allowing arrays of arrays with different content in the inner arrays -

i have next info structure:

data value = vstring text | vinteger integer | vdouble double | vbool bool | varray [value] | vdate utctime deriving (eq, ord, show)

the next arrays valid according value info type:

varray [vinteger 1, vinteger 2] varray [varray [vinteger 1, vinteger 2], varray [vstring "a", vstring "b"]]

now want enforce on type-level next arrays prohibited (while above definition of value allowed):

varray [vinteger 1, vdouble 2.0] varray [varray [vinteger 1, vinteger 2], vbool true]

in other words, want prohibit "mixed" arrays, while allowing arrays of arrays different content in inner arrays. arrays may nested arbitrarily deep levels.

how can alter definition of value (and perchance add together other definitions) facilitate type-level restriction in haskell?

i tried best of ability, found myself stuck... help appreciated.

note: i'm working on parser toml file format, defined arrays mentioned above.

some more context question. how value used (in table, etc.):

data tomldoc = tomldoc table [tablenode] info tablenode = tablenode text (maybe (either table tablearray)) [tablenode] deriving (eq, ord, show) type table = map text value type tablearray = [table]

and how hope build document:

test :: tomldoc test = tomldoc (m.fromlist [("a", vinteger 1), ("b", vinteger 2)]) [ tablenode "a" (just . left $ m.fromlist [("aa", vinteger 1)]) [] , tablenode "b" (just . left $ m.fromlist [("bb", vinteger 2)]) [ tablenode "b" (just . left $ m.fromlist [("bbb", vinteger 2)]) [] , tablenode "c" (just . right $ [ m.fromlist [("bbc", vinteger 2)] , m.fromlist [("bbc", varray [ varray [vinteger 1, vinteger 2], varray [] ])] ]) [] ] ]

some parts of specification unclear. array of arrays nested different levels valid? example, varray [varray [varray [vinteger 1]], varray [vinteger 1]] valid value? cover both variants.

the basic principle tag value type contains:

data value vstring :: text -> value text vinteger :: integer -> value integer vdouble :: double -> value double vbool :: bool -> value bool vdate :: utctime -> value utctime

in case array of nested arrays of different levels valid, have

data array info value .... varray :: [value a] -> value array

in other case, array must know nesting depth, simple store value in array:

data array info value .... varray :: [value a] -> value (array a)

eventually want forget type information. don't know why want this, should carry on using typed version. types should help you, not hinder you. if @ point, types getting in way, doing wrong.

but if want, can erase type: info value .... vuntype :: value -> value ()

type table = map text (value ()) ... test :: tomldoc test = tomldoc (m.fromlist [("a", vuntype $ vinteger 1), ("b", vuntype $ vinteger 2)]) ...

be careful! create introduce a lot of added complexity code in other places:

func0 f (vuntype x) = vuntype (f x)

what type of function?

-- wrong func0 :: (value -> value b) -> value () -> value () func0 :: (value -> value a) -> value () -> value () func0 :: (value integer -> value array) -> value () -> value () func0 :: (forall b . value -> value b) -> value () -> value ()

the lastly 1 dangerous. compile, however, type type forall b . value -> value b uninhabited. function can write type undefined (strictly speaking, have \_ -> undefined).

this right type: func0 :: (forall . value -> value a) -> value () -> value ()

another example:

-- wrong func1 :: (value -> b) -> value () -> b func1 :: (value integer -> b) -> value () -> b -- right func1 :: (forall . value -> b) -> value () -> b func1 f (vuntype x) = f x

if still need access types @ runtime, can a) maintain types way through; b) alter constructor vuntype :: typeable => value -> value ().

the lastly alternative if need utilize type info constructing valid data, , never plan write functions value uses type. take original info type, utilize secondary type phantom type parameter , export typed version of constructors:

data value = vstring text | vinteger integer | vdouble double | vbool bool | varray [value] | vdate utctime newtype safevalue = sv {getsv :: value} -- pick improve name :) vstring :: text -> safevalue text vstring = sv . vstring .... varray :: [safevalue a] -> safevalue array varray = sv . varray . map getsv

this has advantage don't utilize existential types/nasty type erasure, may create hard write typed code. simple write getsv , properly rid of nasty types.

arrays haskell data-structures types

Comments

Popular posts from this blog

formatting - SAS SQL Datepart function returning odd values -

c++ - Apple Mach-O Linker Error(Duplicate Symbols For Architecture armv7) -

php - Yii 2: Unable to find a class into the extension 'yii2-admin' -