haskell - Polymorphic types in records -


i'm trying write function reads raw bytes file, "casts" "plain" type, sorts it.

in order this, need tell sort how should interpret binary data - i.e., type of binary data is.

in order "binary" data, in sense of "i can treat data raw bits, read , write disk", type of data must binary , bits. and, sort it, must member of ord.

any type constrained these ways should sortable.

as little hack, in order pass type sort function, passing inhabitant of type instead. (if there's way pass type , achieve results, i'd love know.)

{-# language rankntypes #-}  import data.binary.get import data.binary.put  type sortable = forall a. (bits a, binary a, ord a) =>  data sortopts = sortopts { maxfiles :: int     , maxmemory :: integer     , maxthreads :: int     , bintype    :: sortable }  defaultopts = sortopts { maxfiles = 128     , maxmemory = 1000 * 1000 * 1000 * 1000     , maxthreads = 4     , bintype = 0 :: word32 };  putbinaryvalues :: binary => handle -> [a] -> io () putbinaryvalues out vals =     let bytes = runput . mapm_ put $ vals     bl.hput out bytes  binaryvalues :: (binary a, bits a) => -> handle -> io [a] binaryvalues t inf =      size <- hfilesize inf     let cast = runget (genericreplicatem (size `div` bytewidth) get)     cast . bl.fromchunks . (:[]) <$> bs.hgetcontents inf     genericreplicatem n = sequence . (dl.genericreplicate n)           bytewidth = fromintegral $ (bitsize t) `div` 8 

but doesn't compile. apparently haskell insists of values of record concrete types. @ least, that's i'm gathering error message:

could not deduce (a ~ word32)     context (bits a, ord a, binary a)         bound type expected context:              (bits a, ord a, binary a) => @ ...     `a' rigid type variable bound         type expected context: (bits a, ord a, binary a) => 

so, how could achieve generalization?

edit:

i wanted use record update syntax "configure" sort. e.g.:

configure = defaultopts -- , exporting 

and later

let myopts = configure{ bintype = 42 :: word16 } 

but doesn't work, , can't quite understand why, unless it's nyi.

record update insufficiently polymorphic field: bintype :: in expression: configure {bintype = words !! 0} in equation `o': o = configure {bintype = words !! 0} in expression:   { intesthandle <- intest;        words <- testrandomwords;        putbinaryvalues intesthandle $ take 100 words;        seekbeg intesthandle;        .... } 

so, client code have copy values out of defaultopts piecemeal , make new record every wants reconfigure sort?

you can use existentialquantification in sortopts type. following compiles:

{-# language existentialquantification #-}  import data.bits import data.word import data.binary import data.binary.get import data.binary.put  data sortopts = forall a. (bits a, binary a, ord a) => sortopts     { maxfiles   :: int     , maxmemory  :: integer     , maxthreads :: int     , bintype    ::     }  defaultopts = sortopts     { maxfiles = 128     , maxmemory = 1000 * 1000 * 1000 * 1000     , maxthreads = 4     , bintype = 0 :: word32     } 

however, note cannot use bintype function because have type exists a. sortopts -> a , cannot existential types return values. can field value pattern matching, example

test :: sortopts -> bytestring -> bytestring -> ordering test (sortopts{bintype=bintype}) bsa bsb = compare b     = runget bsa `astypeof` bintype     b = runget bsb `astypeof` bintype 

this deserializes , compares 2 bytestrings using existential bintype in given sortopts.

as noticed, haskell's record-update syntax doesn't support existential fields, need update bintype:

defaultopts = sortopts     { maxfiles = 128     , maxmemory = 1000 * 1000 * 1000 * 1000     , maxthreads = 4     , bintype = 0 :: word32     }  alternativeopts = withbintype (0 :: word16) $ defaultopts     { maxfiles = 256 }  withbintype :: (bits a, binary a, ord a) => -> sortopts -> sortopts withbintype bt (sortopts{..}) = sortopts maxfiles maxmemory maxthreads bt 

the above uses recordwildcards make copying record bit easier. it's handy extension when using options record later on.

alternatively, jozefg suggested, use wrapper type bintype. use this:

{-# language existentialquantification #-}  data bintype = forall a. (bits a, binary a, ord a) => bintype  data sortopts = sortopts     { maxfiles   :: int     , maxmemory  :: integer     , maxthreads :: int     , bintype    :: bintype     }  defaultopts = sortopts     { maxfiles = 128     , maxmemory = 1000 * 1000 * 1000 * 1000     , maxthreads = 4     , bintype = bintype (0 :: word32)     }  alternativeopts = defaultopts     { bintype = bintype (0 :: word16) } 

since sortopts regular record type can use record operations normally. refer unwrapped bintype, need pattern match on wrapper test example before become (using recordwildcards)

test :: sortopts -> bytestring -> bytestring -> ordering test (sortopts{..}) bsa bsb = case bintype of     bintype bt -> compare b         = runget bsa `astypeof` bt         b = runget bsb `astypeof` bt 

note of above assumes have particular use-case need able hide exact type parameter behind existential reason. normally, leave type-parameter in sortopts , constrain in functions use sortopts. i.e.

data sortopts = sortopts     { maxfiles   :: int     , maxmemory  :: integer     , maxthreads :: int     , bintype    ::     }  test :: (bits a, binary a, ord a) => sortopts -> bytestring -> bytestring -> ordering test (sortopts{..}) bsa bsb = compare b     = runget bsa `astypeof` bintype     b = runget bsb `astypeof` bintype 

you can use constraintkinds extension make shorter alias if needed, in

{-# language constraintkinds #-}  type bintype = (bits a, binary a, ord a)  test :: bintype => sortopts -> bytestring -> bytestring -> ordering 

Comments

Popular posts from this blog

html - How to style widget with post count different than without post count -

How to remove text and logo OR add Overflow on Android ActionBar using AppCompat on API 8? -

javascript - storing input from prompt in array and displaying the array -