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 <ghc-devs@haskell.org> 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 <hessel...@gmail.com 
>> <mailto:hessel...@gmail.com>> 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
> ghc-devs@haskell.org
> http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs

_______________________________________________
ghc-devs mailing list
ghc-devs@haskell.org
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs

Reply via email to