Deconstructing an existential type

后端 未结 3 1830
梦谈多话
梦谈多话 2021-01-15 12:58

I am using an existential type as a wrapper. At a point in my code where I know the enclosed type, I want to do something with it that is specific to the enclosed type. This

3条回答
  •  北荒
    北荒 (楼主)
    2021-01-15 13:27

    You have to convince the type checker as well that you have the type is Bug. You can do this by making Data.Typeable.Typeable a super-class of Agent and then use Data.Typeable.cast to downcast from the existential type to the actual type.

    But before doing this, consider doing it some other way. This is not very Haskellish, but rather in OO style.

    {-# LANGUAGE ExistentialQuantification, DeriveDataTypeable #-}
    import Data.Typeable
    import Data.Maybe
    
    class Typeable a => Agent a where
      agentId :: a -> String
      speciesId :: a -> String
    
    data AgentBox = forall a. Agent a => AgentBox { unbox :: a }
        deriving (Typeable)
    
    instance Agent AgentBox where
      agentId (AgentBox a) = agentId a
      speciesId (AgentBox a) = speciesId a
    
    bugTag :: String
    bugTag = "Bug"
    
    data Bug = Bug String
        deriving (Typeable)
    
    instance Agent Bug where
      agentId (Bug name) = name
      speciesId _ = bugTag
    
    doSomethingWith :: AgentBox -> IO ()
    doSomethingWith a = do
      case cast a of
        Just bug -> doBugStuff bug
        Nothing -> return ()
    
    doBugStuff :: Bug -> IO ()
    doBugStuff a = putStrLn $ agentId a ++ " does bug stuff"
    

提交回复
热议问题