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
dynamicvalue obtain actual value (of existentially quantified typea) stored within, , representation of type (of typetyperep a).it pattern matches on
typerep adetermine if application (usingapp). clearly,delayed aapplication of type constructor, first thing must check.it compares type constructor (the first argument
app)typerepcorrespondingdelayed(note must haveinstance typeable delayedthis). if comparison successful, pattern matches on proof (thatjust hrefl) first argumentapp,delayedin fact same type.at point, compiler knows
a ~ delayed xx. so, can call functionforall . typeable => delayed -> ron valuex :: a. must provide proofxtypeable, given precisely value of typetyperep x-withtypeablereifies value-level proof type-level constraint (alternatively, have input function take argumenttyperep 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
Post a Comment