A followup wish I have:
```hs
case io `eqTypeRep` typeRep @IO of
Just HRefl -> Dynamic TypeRep <$> monotypedAct
Nothing -> naAlt -- not an IO action
```
The `Just HRefl` part as in above remains hard to understand for me, I had
glanced it in doc of the 'Type.Reflection' module earlier, but had no chance to
figure out the usage of `eqTypeRep` to be like this, at least on my own. The
community is very helpful in this regards, in leading me to it. But may there
can be better surface syntax / usage hints that more intuitive, i.e. costing
less effort to reach the solution? I anticipate improvements but apparently
lack expertise for progress, I tried `Just {}` and it won't compile already...
I mean, things are already great as far, well, maybe the learning experience
can be made even better.
Best,
Compl
> On 2021-04-13, at 22:07, YueCompl via ghc-devs <[email protected]> wrote:
>
> After struggled this far, I decide that I can neither trivially understand
> `pattern TypeRep`, nor the `withTypeable` at core. But this is what really
> amazing with Haskell, GHC and the community here - I can get my job done even
> without full understanding of what's going on under the hood, so long as the
> compiler says it's okay! The warning has gone due to unknown reason after I
> refactored the code a bit, surprisingly but well, I feel safe and comfort to
> use it now.
>
> Thanks to Erik, Vlad and Jaro again for your help.
>
> u/Iceland_jack made a ticket to [add pattern TypeRep to
> Type.Reflection](https://gitlab.haskell.org/ghc/ghc/-/issues/19691
> <https://gitlab.haskell.org/ghc/ghc/-/issues/19691>) and appears it's very
> welcomed. Though I don't expect it get shipped very soon or even could be
> back ported to GHC 8.8, so I end up with this shim:
>
> (there `PolyKinds` appears some unusual to be put into my `.cabal` due to its
> syntax change can break some of my existing code)
>
> ```hs
> {-# LANGUAGE PolyKinds #-}
>
> module Dyn.Shim
> ( pattern TypeRep,
> dynPerformIO,
> dynPerformSTM,
> dynContSTM,
> )
> where
>
> import Control.Concurrent.STM (STM)
> import Data.Dynamic (Dynamic (..), Typeable)
> import Type.Reflection
> ( TypeRep,
> eqTypeRep,
> typeRep,
> withTypeable,
> pattern App,
> type (:~~:) (HRefl),
> )
> import Prelude
>
> data TypeableInstance a where
> TypeableInstance :: Typeable a => TypeableInstance a
>
> typeableInstance :: TypeRep a -> TypeableInstance a
> typeableInstance tr = withTypeable tr TypeableInstance
>
> {- ORMOLU_DISABLE -}
>
> -- | Shim for the proposed one at:
> -- https://gitlab.haskell.org/ghc/ghc/-/issues/19691
> <https://gitlab.haskell.org/ghc/ghc/-/issues/19691>
> pattern TypeRep :: forall k (a :: k). () => Typeable a => TypeRep a
> pattern TypeRep <- (typeableInstance -> TypeableInstance)
> where TypeRep = typeRep
>
> {- ORMOLU_ENABLE -}
>
> -- | Perform a polymorphic IO action which is wrapped in a 'Dynamic'
> --
> -- The specified 'naAlt' action will be performed instead, if the wrapped
> -- computation is not applicable, i.e. not really an IO action.
> dynPerformIO :: IO Dynamic -> Dynamic -> IO Dynamic
> dynPerformIO naAlt (Dynamic trAct monotypedAct) = case trAct of
> App io TypeRep ->
> case io `eqTypeRep` typeRep @IO of
> Just HRefl -> Dynamic TypeRep <$> monotypedAct
> Nothing -> naAlt -- not an IO action
> _ -> naAlt -- not even a poly-type
>
> -- | Perform a polymorphic STM action which is wrapped in a 'Dynamic'
> --
> -- The specified 'naAlt' action will be performed instead, if the wrapped
> -- computation is not applicable, i.e. not really an STM action.
> dynPerformSTM :: STM Dynamic -> Dynamic -> STM Dynamic
> dynPerformSTM naAlt (Dynamic trAct monotypedAct) = case trAct of
> App io TypeRep ->
> case io `eqTypeRep` typeRep @STM of
> Just HRefl -> Dynamic TypeRep <$> monotypedAct
> Nothing -> naAlt -- not an STM action
> _ -> naAlt -- not even a poly-type
>
> -- | Perform a polymorphic STM action which is wrapped in a 'Dynamic'
> --
> -- The specified 'naAlt' action will be performed instead, if the wrapped
> -- computation is not applicable, i.e. not really an STM action.
> dynContSTM :: STM () -> Dynamic -> (Dynamic -> STM ()) -> STM ()
> dynContSTM naAlt (Dynamic trAct monotypedAct) !exit = case trAct of
> App io TypeRep ->
> case io `eqTypeRep` typeRep @STM of
> Just HRefl -> exit . Dynamic TypeRep =<< monotypedAct
> Nothing -> naAlt -- not an STM action
> _ -> naAlt -- not even a poly-type
>
> ```
>
> And my test case being a little more complex than the very first example,
> might be easier for others to grasp the usage, it runs like this:
>
> ```console
> λ> import PoC.DynPoly
> λ> testDynHold
> First got Nothing
> Then got Just 3
> λ>
> ```
>
> With the code:
>
> ```hs
> module PoC.DynPoly where
>
> import Control.Monad (void)
> import Data.Dynamic (Dynamic (..), fromDynamic, toDyn)
> import Data.IORef (modifyIORef', newIORef, readIORef, writeIORef)
> import Dyn.Shim
> import Type.Reflection (eqTypeRep, typeRep, pattern App, type (:~~:) (HRefl))
> import Prelude
>
> dynHoldEvent :: Dynamic -> Dynamic
> dynHoldEvent (Dynamic trEvs monotypedEvs) =
> case trEvs of
> App trEs TypeRep ->
> case trEs `eqTypeRep` typeRep @EventSink of
> Just HRefl -> Dynamic TypeRep (holdEvent monotypedEvs)
> Nothing -> error "not an EventSink" -- to be handled properly
> _ -> error "even not a poly-type" -- to be handled properly
> where
> holdEvent :: forall a. EventSink a -> IO (TimeSeries a)
> holdEvent !evs = do
> !holder <- newIORef Nothing
> listenEvents evs $ writeIORef holder . Just
> return $ TimeSeries $ readIORef holder
>
> data EventSink a = EventSink
> { listenEvents :: (a -> IO ()) -> IO (),
> publishEvent :: a -> IO ()
> }
>
> newtype TimeSeries a = TimeSeries {readTimeSeries :: IO (Maybe a)}
>
> newEventSink :: forall a. IO (EventSink a)
> newEventSink = do
> !listeners <- newIORef []
> let listen listener = modifyIORef' listeners (listener :)
> publish a = readIORef listeners >>= void . mapM ($ a)
> return $ EventSink listen publish
>
> testDynHold :: IO ()
> testDynHold = do
> (evs :: EventSink Int) <- newEventSink
> let !dynEvs = toDyn evs
> !dynHold = dynHoldEvent dynEvs
> !dynTs <- dynPerformIO (error "bug: dyn type mismatch?") dynHold
> case fromDynamic dynTs of
> Nothing -> error "bug: unexpected dyn result type"
> Just (ts :: TimeSeries Int) -> do
> v0 <- readTimeSeries ts
> putStrLn $ "First got " <> show v0
> publishEvent evs 3
> v1 <- readTimeSeries ts
> putStrLn $ "Then got " <> show v1
> ```
>
> Thanks with best regards,
> Compl
>
>
>> On 2021-04-13, at 02:50, Erik Hesselink <[email protected]
>> <mailto:[email protected]>> wrote:
>>
>> That is a lot, I'm not sure I understand that pattern synonym. Using
>> `withTypeable` instead works for me:
>>
>> holdEvent :: Dynamic -> Dynamic
>> holdEvent (Dynamic tr x) =
>> case tr of
>> App ft at ->
>> case ft `eqTypeRep` typeRep @EventSink of
>> Just HRefl -> withTypeable at $ toDyn (hcHoldEvent x)
>> Nothing -> error "to handle"
>> _ -> error "to handle"
>>
>> Cheers,
>>
>> Erik
>
> _______________________________________________
> ghc-devs mailing list
> [email protected]
> http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
_______________________________________________
ghc-devs mailing list
[email protected]
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs