问题描述
我使用存在类型作为包装。在我知道封闭类型的代码中,我想对它做一些特定于封闭类型的事情。这是我能得到的最接近的:
$ $ 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`模型)
失败,模块加载:无。
我该如何做到这一点?预先感谢您的任何建议。 使用。
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
类型是,所以你应该忽略一下我已经写过上面的内容,并且将 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.
这篇关于解构存在型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!