将打印文本的函数作为参数传递,在 Haskell 中的新状态之后执行它

如何解决将打印文本的函数作为参数传递,在 Haskell 中的新状态之后执行它

[EDIT3:一个包含几乎完整代码文件

https://github.com/agutie58/landOfLispInHaskell/blob/main/exampleLoLTextGameHaskell.hs

EDIT2:实际游戏的一个例子。]


[原始问题]
我有一个基于 run函数 Domain一个事件列表:

  • 如果处理了所有事件,它会侦听新事件并
  • 如果它们是事件,它会处理其中的几个。

大多数事件都会修改 Domain

data Domain =   Domain (String,World) deriving (Show)
data World = World {loc :: String,descSites :: [(Key,String)],mapSites :: [(Key,[Lloc])],objects:: [Key],siteObjects::[(Key,String)]}  deriving (Show)


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

我想要关注的部分是 run (dmUpdate dm e) es,其中 dmUpdate dm e 返回一个 Domain 值:

函数 dmUpdate 运行良好的一个示例是:

dmUpdate :: Domain -> Event  ->  Domain

dmUpdate (Domain v) (EventLook) =  look (snd v) 
                                               
dmUpdate (Domain v) (EventWalk direction) =  walk direction (snd v) 

dmUpdate dm _ _ = dm 

哪里:

look :: World -> Domain
walk :: String -> World -> Domain
-- etc.

我想呈现(打印到控制台)新状态的结果。例如:

dmUpdate (Domain v) (EventLook) =  do let newDomain = look (snd v) 
                                          putStr (fst newDomain)
                                          newDomain

但它不起作用。我尝试计算世界的新状态,然后执行 I/O,然后尝试将 newDomain 作为参数返回。

我想传递这样的函数

run dm (e:es) =
  run (dmUpdate dm e renderMsg) es
  where renderMsg txt = (putStr txt) >> (hFlush stdout)

...为了做类似的事情:

-- dmUpdate :: dmUpdate :: Domain -> Event -> (String -> IO ()) -> IO () -> Domain
dmUpdate (Domain v) (EventLook) (renderMsg) =  let newDomain = look (snd v) 
                                               renderMsg (fst newDomain)

但不起作用。

任何想法!?提前致谢!


[EDIT1]
我也试过:

  dmUpdate :: Domain -> Event  -> IO Domain
    dmUpdate (Domain v) (EventLook) =  do let newDomain = look (snd v) 
                                          putStr (fst newDomain)
                                          newDomain
                                                                                        
    
    dmUpdate dm _ _ = () dm 

...但我收到了这条消息:

[2 of 2] Compiling Main             ( textGameMain.hs,interpreted )

textGameMain.hs:25:1: error:
    Equations for ‘dmUpdate’ have different numbers of arguments
      textGameMain.hs:(25,1)-(27,47)
      textGameMain.hs:33:1-23
   |
25 | dmUpdate (Domain v) (EventLook) =  do let newDomain = look (snd v) 
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^...

textGameMain.hs:70:8: error:
    • Couldn't match expected type ‘Domain’
                  with actual type ‘IO 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
   |
70 |   run (dmUpdate dm e ) es

然后,我尝试更改run

run dm (e:es) =
  run () (dmUpdate dm e ) es

但我没有设法让它工作...... :S


[EDIT2]
所以,我的代码是这样做的(它基于 Land of Lisp,并且是对 Haskell 的改编):


    *Main> main
    WORLD> look
    you are in the living-room. a wizard is snoring loudly on the couch.
    There is door going west from here.
    There is ladder going upstairs from here.
    You see a whiskey on the floor.
    You see a bucket on the floor. 
    
    WORLD> walk west
    WORLD> look
    you are in a beautiful garden. there is a well in front of you.
    There is door going east from here.
    You see a frog on the floor.
    You see a chain on the floor. 


[EDIT3]
(完整代码 - 实际上,为了简单起见,我将两个文件合并为一个文件……可以通过其他方式添加文件吗!?)

https://github.com/agutie58/landOfLispInHaskell/blob/main/exampleLoLTextGameHaskell.hs

ghci exampleLoLTextGameHaskell.hs
main

(...然后,要编辑 2 的东西...)

解决方法

您的代码远未完成,包含很多 - 对于您的问题 - 不必要的部分。我复制了你的代码,简化了一点,并做了一些猜测工作。这是我的“固定”版本。

module Tmp where
import Text.Read (readMaybe)

{-| Be clear about your types. Introducing type alisases helps others read your code.
 I simply guessed that the string-part of the Domain is the UI state -}
type UIState = String
data Domain = Domain (UIState,World) deriving Show
data World = World {loc:: Int} deriving Show

-- | I Have only implemented two directions,so that this example is easy to work with.
data Dir = L | R deriving (Read,Show)

{- | These were the event types that you had in your code. I elaborated them a little. 
By using the "deriving (Read)" we get a low-code input mechanism,but you should probalbly write
your own input parser
-} 
data Event = EventExit | EventWalk Dir| EventLook deriving (Read)

-- | The run-loop now has TWO steps. Render UI and get new events. Process events. Finally recurse.
run :: Domain -> [Event] -> IO ()
run dm [] = uiUpdate dm >> getAction >>= run dm
run _ (EventExit:_) = return ()
run dm (e:es) = run (dmUpdate dm e) es

{-| Update the domain when a single event acts on it -}
dmUpdate :: Domain -> Event -> Domain
dmUpdate (Domain v) (EventLook) =  look (snd v) 
dmUpdate (Domain v) (EventWalk direction) =  walk direction (snd v)
dmUpdate dm _ = dm

look w = Domain ("You are at coordinate " ++ (show .loc $ w),w)
walk L w@World{loc=l}= Domain ("You went left",w{loc=l-1})
walk R w@World{loc=l} = Domain  ("You went right",w{loc=l+1})

{-| Present the "output" that the domain holds for us -}
uiUpdate :: Domain -> IO ()
uiUpdate dm = do
    let Domain (usState,s) = dm
    putStrLn usState

{-| Ask user for input. Only a single event is collected. -}
getAction :: IO [Event]
getAction = do
    putStrLn "What do you want to do? Choose between EventExit | EventWalk R | EventWalk L | EventLook"
    act <- readMaybe <$> getLine
    case act of 
        Nothing -> putStrLn "Not a valid action" >> getAction
        Just evt -> pure [evt]


main :: IO ()
main = run  (Domain ("",World 0)) [EventLook]

最后,您可能想要查看 StateT,以便您可以抽象出一直传递的 Domain 对象。但这超出了这个问题的范围,我想。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?