How can I recover sharing in a GADT?

后端 未结 2 750
面向向阳花
面向向阳花 2021-02-05 08:06

In Type-Safe Observable Sharing in Haskell Andy Gill shows how to recover sharing that existed on the Haskell level, in a DSL. His solution is implemented in the data-reify pack

2条回答
  •  佛祖请我去吃肉
    2021-02-05 08:39

    Interesting puzzle! It turns out you can use data-reify with GADTs. What you need is a wrapper that hides the type in an existential. The type can later be retrieved by pattern matching on the Type data type.

    data Type a where
      Bool :: Type Bool
      Int :: Type Int
    
    data WrappedAst s where
      Wrap :: Type e -> Ast2 e s -> WrappedAst s
    
    instance MuRef (Ast e) where
      type DeRef (Ast e) = WrappedAst
      mapDeRef f e = Wrap (getType e) <$> mapDeRef' f e
        where
          mapDeRef' :: Applicative f => (forall b. (MuRef b, WrappedAst ~ DeRef b) => b -> f u) -> Ast e -> f (Ast2 e u)
          mapDeRef' f (IntLit i) = pure $ IntLit2 i
          mapDeRef' f (Add a b) = Add2 <$> (Var Int <$> f a) <*> (Var Int <$> f b)
          mapDeRef' f (BoolLit b) = pure $ BoolLit2 b
          mapDeRef' f (IfThenElse b t e) = IfThenElse2 <$> (Var Bool <$> f b) <*> (Var (getType t) <$> f t) <*> (Var (getType e) <$> f e)
    
    getVar :: Map Name (WrappedAst Name) -> Type e -> Name -> Maybe (Ast2 e Name)
    getVar m t n = case m ! n of Wrap t' e -> (\Refl -> e) <$> typeEq t t'
    

    Here's the whole code: https://gist.github.com/3590197

    Edit: I like the use of Typeable in the other answer. So I did a version of my code with Typeable too: https://gist.github.com/3593585. The code is significantly shorter. Type e -> is replaced by Typeable e =>, which also has a downside: we no longer know that the possible types are limited to Int and Bool, which means there has to be a Typeable e constraint in IfThenElse.

提交回复
热议问题