【发布时间】:2021-09-14 11:06:19
【问题描述】:
我正在尝试基于此示例在 Haskell 中使用事件架构(效果很好): https://wiki.haskell.org/Real_World_Applications/Event_Driven_Applications
我尝试将此代码应用于更复杂的示例。这个想法是在 Haskell 中以最自然的方式改变一个对象(比如说域):
data Domain =
Domain (String, World)
... 对 World 执行几个命令并更改它(或在元组的第一个参数中得到消息)。
With World a "class" of type:
data World = World {loc :: String, descLlocs :: [(String,String)]} deriving (Show)
但是当一个 EventLook 启动时,例如
dmUpdate :: Domain -> Event -> Domain
dmUpdate (Domain v) (EventLook) = do
let msg = fst v
let newWorld = snd v
-- Maybe IO Action !? Is possible !?
return Domain (msg, newWorld)
dmUpdate dm _ = dm
我收到了这个错误(在我看来,“Domain (msg, newWorld)”的类型是:Domain,不!?(我也尝试返回 (msg, newWorld) 没有成功)。
baseEventDomainProgram.hs:30:35: error:
• Couldn't match type ‘(String, World) -> Domain’ with ‘Domain’
Expected type: (String, World) -> Domain
Actual type: (String, World) -> (String, World) -> Domain
• The function ‘return’ is applied to two arguments,
but its type ‘((String, World) -> Domain)
-> (String, World) -> (String, World) -> Domain’
has only three
In a stmt of a 'do' block: return Domain (msg, newWorld)
In the expression:
do let msg = fst v
let newWorld = snd v
return Domain (msg, newWorld)
|
30 | return Domain (msg, newWorld)
因此,我的想法只是通过 newWorld 来计算新状态(更改对象的数据)。 我可以添加这个玩具示例。
import System.IO
data Event =
EventExit -- User wants to exit
| EventLook
| EventAdd Int
deriving(Eq,Show)
data World = World {loc :: String, descLlocs :: [(String,String)]} deriving (Show)
theWorld = World {loc = "living-room", descLlocs = [("living-room","you are in the living-room. a wizard is snoring loudly on the couch.")
,("garden","you are in a beautiful garden. there is a well in front of you.")
, ("attic", "you are in the attic. there is a giant welding torch in the corner.")]}
data Domain =
Domain (String, World)
dmUpdate :: Domain -> Event -> Domain
dmUpdate (Domain v) (EventLook) = do
let msg = fst v
let newWorld = snd v
-- Maybe IO Action !?
return (Domain (msg, newWorld))
dmUpdate dm _ = dm
uiUpdate :: Domain -> IO [Event]
uiUpdate (Domain v) = do
putStrLn $ "WORLD> " ++ show (fst v)
input <- read'
if input == ":quit" then
return [EventExit]
else
return [EventLook]
run :: Domain -> [Event] -> IO ()
run dm [] = do
events <- uiUpdate dm
run dm events
run _ (EventExit:_) =
return ()
run dm (e:es) =
run (dmUpdate dm e) es
read' :: IO String
read' = putStr "WORLD> "
>> hFlush stdout
>> getLine
main :: IO ()
main = run (Domain ("",theWorld)) []
提前致谢!
编辑: 正如@jpmarinier 所指出的,代码应该只返回一个参数,所以:“return (Domain (msg,newWorld))”应该更好。所以我编辑了与这个正确句子共享的代码。
但在这种情况下,我遇到了两个错误:
baseEventDomainProgram.hs:31:17: error:
• Couldn't match expected type ‘m Domain’ with actual type ‘Domain’
• In the expression: dm
In an equation for ‘dmUpdate’: dmUpdate dm _ = dm
• Relevant bindings include
dmUpdate :: Domain -> Event -> m Domain
(bound at baseEventDomainProgram.hs:26:1)
|
31 | dmUpdate dm _ = dm
| ^^
baseEventDomainProgram.hs:51:8: error:
• Couldn't match expected type ‘Domain’
with actual type ‘m0 Domain’
• In the first argument of ‘run’, namely ‘(dmUpdate dm e)’
In the expression: run (dmUpdate dm e) es
In an equation for ‘run’: run dm (e : es) = run (dmUpdate dm e) es
|
51 | run (dmUpdate dm e) es
| ^^^^^^^^^^^^^
【问题讨论】:
-
错误消息显示
The function ‘return’ is applied to two arguments。你试过return $ Domain (msg, newWorld)或return (Domain (msg, newWorld))吗? -
是的,其实我尝试了好几件事,但都没有成功(但你是对的),带return (Domain (msg,newWorld)) 的版本应该会更好。不过我得到了这个错误:
-
baseEventDomainProgram.hs:31:17: 错误: • 无法将预期类型“m Domain”与实际类型“Domain”匹配 • 在表达式中:dm 在“dmUpdate”等式中:dmUpdate dm _ = dm • 相关绑定包括dmUpdate :: Domain -> Event -> m Domain(绑定在baseEventDomainProgram.hs:26:1)| 31 | dmUpdate dm _ = dm |
-
非常感谢您的解释!你完全正确,我误解了“return”命令,我不明白为什么 Haskell 强迫我使用 monad。
标签: haskell events monads drive