解构存在型 [英] Deconstructing an existential type

查看:114
本文介绍了解构存在型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用存在类型作为包装。在我知道封闭类型的代码中,我想对它做一些特定于封闭类型的事情。这是我能得到的最接近的:

$ $ p $ { - #LANGUAGE ExistentialQuantification# - }

class Agent a where
agentId :: a - >字符串
speciesId :: a - >字符串
- 加上所有代理支持的其他功能

- |一个封装程序允许我的守护进程读写任何物种的代理。
- (代理存储在包含标签的文件中,因此我知道哪个函数
- 可以调用以读取代理。)
data AgentBox = forall a。 Agent a => AgentBox {unbox :: a}

实例Agent AgentBox其中
agentId(AgentBox a)= agentId a
speciesId(AgentBox a)= speciesId a
- plus所有代理支持的其他功能

bugTag :: String
bugTag =Bug

数据Bug = Bug字符串

实例代理Bug
agentId(Bug name)= name
speciesId _ = bugTag

doSomethingWith :: AgentBox - > IO()
doSomethingWith a = do
if speciesId a == bugTag
然后做
- 现在我知道这是一个bug,我想做一些bug特定的
doBugStuff2 a
return()
else return()

doBugStuff :: Bug - > IO()
doBugStuff a = putStrLn $ agentId a ++做错误的东西

doBugStuff2 AgentBox {unbox = a} = doBugStuff(a`asTypeOf`模型) - 第39行
where model = undefined :: Bug

我得到的错误是:

  Amy30.hs:39:45:
无法从上下文中推断(a〜Bug)
(Agent a)
由构造函数
绑定的模式AgentBox :: forall a。 Agent a => a - > AgentBox,
在`doBugStuff2'的等式中
在Amy30.hs:39:13-29
`a'是一个刚性类型变量,由$ b $绑定,具有构造函数
AgentBox :: forall a。 Agent a => a - > AgentBox,
在`doBugStuff2'的等式中
在Amy30.hs:39:13
在`asTypeOf'的第一个参数中,即`a'
在第一个参数
`(a`asTypeOf`模型)'
在表达式中:doBugStuff(a`asTypeOf`模型)
失败,模块加载:无。

我该如何做到这一点?预先感谢您的任何建议。 使用 Data.Dynamic

  import Data.Dynamic 

class Typeable a => Agent a其中
agentId :: a - >字符串
- 不需要speciesId

来自AgentBox :: Agent a => AgentBox - >从代理盒(AgentBox内部)= fromDynamic(toDyn内部)

实例代理Bug其中
agentId(Bug名称)=名称
- 不需要speciesId

doSomethingWith :: AgentBox - > IO()
doSomethingWith a = do
来自AgentBox a
只是bug - >做
- 现在编译器知道这是一个bug,我可以做一些bug特定的
doBugStuff2 bug
return()
Nothing - >返回()

或者,考虑声明 doSomethingWith Agent 类中,可能使用默认定义。

  class Agent a where 
agentId :: a - >字符串
- 仍然不需要speciesId
doSomethingWith :: a - > IO()
doSomethingWith _ = return()

实例代理错误其中
agentId(错误名称)=名称
- 仍然不需要speciesId
doSomethingWith bug = do
- 现在编译器知道这是一个bug,我可以做一些特定于bug的bug
doBugStuff2 bug
return()

最后,我应该指出你的 AgentBox 类型是 existential typeclass anti-pattern ,所以你应该忽略一下我已经写过上面的内容,并且将 Agent 类重新设计为普通数据类型。


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 is the closest I can get:

 {-# LANGUAGE ExistentialQuantification #-}

class Agent a where
  agentId :: a -> String
  speciesId :: a -> String
  -- plus other functions that all agents support

-- | A wrapper allowing my daemon to read and write agents of any species.
--   (Agents are stored in files that contain a tag so I know which function
--   to call to read the agent.)
data AgentBox = forall a. Agent a => AgentBox { unbox :: a }

instance Agent AgentBox where
  agentId (AgentBox a) = agentId a
  speciesId (AgentBox a) = speciesId a
  -- plus other functions that all agents support

bugTag :: String
bugTag = "Bug"

data Bug = Bug String

instance Agent Bug where
  agentId (Bug name) = name
  speciesId _ = bugTag

doSomethingWith :: AgentBox -> IO ()
doSomethingWith a = do
  if speciesId a == bugTag
    then do
      -- Now I know it's a bug, and I want to do something bug-specific
      doBugStuff2 a
      return ()
    else return ()

doBugStuff :: Bug -> IO ()
doBugStuff a = putStrLn $ agentId a ++ " does bug stuff"

doBugStuff2 AgentBox{unbox=a} = doBugStuff (a `asTypeOf` model) -- line 39
  where model = undefined :: Bug

The error I get is:

Amy30.hs:39:45:
    Could not deduce (a ~ Bug)
    from the context (Agent a)
      bound by a pattern with constructor
                 AgentBox :: forall a. Agent a => a -> AgentBox,
               in an equation for `doBugStuff2'
      at Amy30.hs:39:13-29
      `a' is a rigid type variable bound by
          a pattern with constructor
            AgentBox :: forall a. Agent a => a -> AgentBox,
          in an equation for `doBugStuff2'
          at Amy30.hs:39:13
    In the first argument of `asTypeOf', namely `a'
    In the first argument of `doBugStuff', namely
      `(a `asTypeOf` model)'
    In the expression: doBugStuff (a `asTypeOf` model)
Failed, modules loaded: none.

How can I accomplish this? Thank you in advance for any suggestions.

解决方案

Use Data.Dynamic.

import Data.Dynamic

class Typeable a => Agent a where
  agentId :: a -> String
  -- no need for speciesId

fromAgentBox :: Agent a => AgentBox -> Maybe a
fromAgentBox (AgentBox inner) = fromDynamic (toDyn inner)

instance Agent Bug where
  agentId (Bug name) = name
  -- no need for speciesId

doSomethingWith :: AgentBox -> IO ()
doSomethingWith a = do
  case fromAgentBox a of
    Just bug -> do
      -- Now the compiler knows it's a bug, and I can do something bug-specific
      doBugStuff2 bug
      return ()
    Nothing -> return ()

Alternatively, consider declaring doSomethingWith in the Agent class, perhaps with a default definition.

class Agent a where
  agentId :: a -> String
  -- still don't need speciesId
  doSomethingWith :: a -> IO ()
  doSomethingWith _ = return ()

instance Agent Bug where
  agentId (Bug name) = name
  -- still don't need speciesId
  doSomethingWith bug = do
    -- Now the compiler knows it's a bug, and I can do something bug-specific
    doBugStuff2 bug
    return ()

Finally, I should point out that your AgentBox type is an example of the existential typeclass anti-pattern, so you should perhaps ignore what I've written above and redesign your Agent class as an ordinary datatype.

这篇关于解构存在型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆