gpt4 book ai didi

haskell - 解构存在类型

转载 作者:行者123 更新时间:2023-12-01 15:32:10 26 4
gpt4 key购买 nike

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

 {-# 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

我得到的错误是:

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.

我怎样才能做到这一点?预先感谢您提出任何建议。

最佳答案

使用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 ()

或者,考虑在 Agent 类中声明 doSomethingWith,也许使用默认定义。

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 ()

最后,我应该指出您的 AgentBox 类型是 existential typeclass anti-pattern 的一个示例,所以您或许应该忽略我上面写的内容,并将您的 Agent 类重新设计为普通数据类型。

关于haskell - 解构存在类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12842426/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com