haskell - How to convert Dynamic to Forall something -


i have cache dynamic values. of them have type delayed a.

normally when access cache, know type a, it's not problem, can use fromdynamic cast maybe a.

i call function doesn't need know type a on list of dynamic. (the method cancel :: delay -> io ()). there way ?

basically need way dynamic forall . delayed a ?

edit

for information, delayed holds pending asynchronous value , mvar start or cancel it. equivalent to

 data delayed m = delayed { blocker :: mvar bool, async :: async m } 

such values stored in cache (which use dynamic , store other things). when displaying cache status, need able status of delayed value (which involve accessing blocker has nothing actual value.

a value of type forall . x a value can instantiated of x int, x bool, x string, etc. presumably, cache stores values of many different types, no single value valid @ every possible type parameter. need value of type exists . delayed a. however, haskell doesn't have first-class existential quantifiers, must encode type in way. 1 particular encoding is:

casttodelayed :: (forall . typeable => delayed -> r) -> dynamic -> r 

assume have function; can write casttodelayed cancel :: dynamic -> io (). note function parameter casttodelayed provides typeable constraint, can freely ignore constraint (which cancel doing). note function must partial due type alone (clearly not every dynamic delayed a a), in real code, should produce e.g. maybe r instead. here elide detail , throw error.

how write function depend on version of ghc using (the recent, 8.2, or older version). on 8.2, nice, simple function:

{-# language viewpatterns #-} -- nb: requires other extensions  import data.dynamic import type.reflection  casttodelayed :: (forall . typeable => delayed -> r) -> dynamic -> r casttodelayed k (dynamic (app (eqtyperep (typerep :: typerep delayed) -> hrefl) a) x)   = withtypeable (k x)  casttodelayed _ _ = error "not delayed" 

(aside: @ first thought con pattern synonym useful here, on deeper inspection seems entirely useless. must use eqtyperep instead.)

briefly, function works follows:

  • it pattern matches on dynamic value obtain actual value (of existentially quantified type a) stored within, , representation of type (of type typerep a).

  • it pattern matches on typerep a determine if application (using app). clearly, delayed a application of type constructor, first thing must check.

  • it compares type constructor (the first argument app) typerep corresponding delayed (note must have instance typeable delayed this). if comparison successful, pattern matches on proof (that just hrefl) first argument app , delayed in fact same type.

  • at point, compiler knows a ~ delayed x x. so, can call function forall . typeable => delayed -> r on value x :: a. must provide proof x typeable, given precisely value of type typerep x - withtypeable reifies value-level proof type-level constraint (alternatively, have input function take argument typerep a, or omit constrain altogether, since specific use case doesn't need it; type general possible).

on older versions, principle same. however, typerep did not take type parameter then; can pattern match on discover if typerep corresponding delayed, cannot prove compiler value stored inside dynamic has type delayed x x. therefore require unsafecoerce, @ step applying function k value x. furthermore, there no withtypeable before ghc 8.2, have write function type (forall . delayed -> r) -> dynamic -> r instead (which, fortunately, enough use case); or implement such function (see source of function see how; implementation on older versions of ghc similar, have type typerep -> (forall . typeable => proxy -> r) -> r instead).

here how implement in ghc < 8.2 (tested on 8.0.2). horrible hack, , make no claim correctly in circumstances.

{-# language derivedatatypeable, magichash, scopedtypevariables, polykinds, viewpatterns #-}  import data.dynamic import data.typeable import unsafe.coerce import ghc.prim (proxy#) import data.proxy  -- part reifies `typeable' dictionary `typerep'. -- works because `typeable' class single field,  -- operationally `typeable => r' same `(proxy# -> typerep) -> r' newtype magictypeable r (kp :: kproxy k) =   magictypeable (forall (a :: k) . typeable => proxy -> r)  withtyperep :: magictypeable r (kp :: kproxy k)             -> forall . typerep -> proxy -> r withtyperep d t = unsafecoerce d ((\_ -> t) :: proxy# -> typerep)  withtypeable :: forall r . typerep -> (forall (a :: k) . typeable => proxy -> r) -> r withtypeable t k = withtyperep (magictypeable k) t proxy  -- type constructor delayed delayed_tycon = fst $ splittyconapp $ typerep (proxy :: proxy delayed)  -- needed because dynamic doesn't export constructor, , -- need pattern match on it. data dynamic = dynamic typerep  unsafeviewdynamic :: dynamic -> dynamic unsafeviewdynamic = unsafecoerce  -- actual implementation, same 1 on ghc 8.2, more  -- 'unsafe' things casttodelayed :: (forall . typeable => delayed -> r) -> dynamic -> r casttodelayed k (unsafeviewdynamic -> dynamic t x) =   case splittyconapp t of     (((== delayed_tycon) -> true), [a]) ->       withtypeable $ \(_ :: proxy (a :: *)) -> k (unsafecoerce x :: delayed a)     _ -> error "not delayed" 

i don't know delayed is, lets assume it's defined follows testing purposes:

data delayed = | none deriving (typeable, show) 

then consider simple test case:

test0 :: typeable => delayed -> string test0 (some x) = maybe "not string" id $ cast x test0 none     = "none"  test0' =   let c = casttodelayed test0 in    [ c (todyn (none :: delayed int))    , c (todyn (some 'a'))    , c (todyn (some "a")) ] 

Comments

Popular posts from this blog

PHP and MySQL WP -

android - InAppBilling registering BroadcastReceiver in AndroidManifest -

go - golang pprof for c library code -