Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 与哈斯凯尔州立大学打交道_Haskell_Functional Programming_State - Fatal编程技术网

Haskell 与哈斯凯尔州立大学打交道

Haskell 与哈斯凯尔州立大学打交道,haskell,functional-programming,state,Haskell,Functional Programming,State,因此,我尝试使用状态实现一个Haskell游戏,作为游戏的一部分,我想实现保存当前玩家的名字并在调用时检索它的方法。我有两个助手函数popStack和pushStack,它们分别将值弹出和推入堆栈 当前代码: import Control.Monad.State data Gamestate = Gamestate { gamestack :: [String], gamememory :: String } type NewGameState = State G

因此,我尝试使用状态实现一个Haskell游戏,作为游戏的一部分,我想实现保存当前玩家的名字并在调用时检索它的方法。我有两个助手函数popStack和pushStack,它们分别将值弹出和推入堆栈

当前代码:

 import Control.Monad.State

 data Gamestate = Gamestate {
     gamestack :: [String],
     gamememory :: String
 }

 type NewGameState = State GameState

 popStack :: NewGameState String
 popStack = state $ \st -> case gamestack st of
     [] -> (0.0,st)
     x:xs -> (x,st { gamestack = xs })

 pushStack :: String -> NewGameState ()
 push d = modify  $ \st -> st { gamestack = d : gamestack st }
我为saveName和getName编写了以下代码

saveName :: NewGameState ()
saveName = do
        memory <-head   
        pushStack $ x

getName :: NewGameState ()
getName = do
        memory <- head gamestack
        popStack $ memory
saveName::NewGameState()
saveName=do

内存如果某个东西位于
=pushStack的右侧。游戏记忆
如果你想成为一名花花公子


popStack
不接受任何参数,因此我不确定您想要什么。我最好的猜测是,它应该只抓取我们推送的姓氏,如果某个东西在
=pushStack的右侧,它就是对
popStack的调用。游戏记忆
如果你想成为一名花花公子


popStack
不接受任何参数,因此我不确定您想要什么。我的最佳猜测是,它应该只抓取我们推的姓氏,这只是对
popStack

的一个调用。我将通过向您展示执行您试图执行的操作的惯用方法来回答您的问题。我将指出我在你的代码中修正了什么

第一个问题:游戏状态的大小写不一致。在Haskell中,大写很重要,所以我将所有内容重命名为
GameState

所以在做了修复之后,我做的第一件事就是为两个数据类型的字段定义镜头。这使得修改状态子集的有状态操作变得更加容易。当我谈到其余函数的实现时,您将看到这一点:

import Control.Monad.State
import Control.Lens

data GameState = GameState
    { _gamestack  :: [String]
    , _gamememory ::  String
    }

gamestack :: Lens' GameState [String]
gamestack k (GameState s m) = fmap (\s' -> GameState s' m) (k s)

gamememory :: Lens' GameState String
gamememory k (GameState s m) = fmap (\m' -> GameState s m') (k m)

type NewGameState = State GameState
请注意,您不必像这样手动定义镜头。除了定义
gamememory
gamestack
,您还可以这样做:

{-# LANGUAGE TemplateHaskell #-}  -- Note the extension

import Control.Lens

data GameState = GameState
    { _gamestack  :: [String]
    , _gamememory ::  String
    }

makeLenses ''GameState
无论您选择哪种方式,一旦我们有了这些镜头,我们就可以编写
push
pop
,只要是一个列表,他们就不关心自己的行为状态:

pop :: State [a] (Maybe a)
pop = do
    s <- get
    case s of
        []   -> return Nothing
        x:xs -> do
            put xs
            return (Just x)

push :: a -> State [a] ()
push d = modify (d:)
请注意,我是如何使用
zoom
来本地化
push
pop
来操作
gamememory
gamestack
字段的<代码>缩放
将镜头移到子字段,然后运行有状态操作,就好像整个状态就是该子字段一样。这很酷,因为现在
push
pop
的可重用性更高,我们不必在其中加入特定的状态数据类型选择

这还使用
=
,设置给定字段。这基本上与:

lens .= x = zoom lens (put x)
要了解更多有关镜头、
(.=)
变焦的信息,您可能需要阅读我写的内容

编辑:根据要求,以下是无镜头版本:

import Control.Monad.State

data GameState = GameState
    { gamestack  :: [String]
    , gamememory ::  String
    }

type NewGameState = State GameState

saveName :: NewGameState ()
saveName = do
    GameState stack memory <- get
    put (GameState (memory:stack) memory)

getName :: NewGameState ()
getName = do
    GameState stack memory <- get
    case stack of
        []   -> put (GameState stack memory)
        x:xs -> put (GameState xs    x     )
import Control.Monad.State
数据游戏状态=游戏状态
{游戏堆栈::[字符串]
,gamememory::String
}
键入NewGameState=状态GameState
saveName::NewGameState()
saveName=do
游戏状态堆栈内存放置(游戏状态xs x)

我将通过向您展示做您想做的事情的惯用方法来回答您的问题。我将指出我在你的代码中修正了什么

第一个问题:游戏状态的大小写不一致。在Haskell中,大写很重要,所以我将所有内容重命名为
GameState

所以在做了修复之后,我做的第一件事就是为两个数据类型的字段定义镜头。这使得修改状态子集的有状态操作变得更加容易。当我谈到其余函数的实现时,您将看到这一点:

import Control.Monad.State
import Control.Lens

data GameState = GameState
    { _gamestack  :: [String]
    , _gamememory ::  String
    }

gamestack :: Lens' GameState [String]
gamestack k (GameState s m) = fmap (\s' -> GameState s' m) (k s)

gamememory :: Lens' GameState String
gamememory k (GameState s m) = fmap (\m' -> GameState s m') (k m)

type NewGameState = State GameState
请注意,您不必像这样手动定义镜头。除了定义
gamememory
gamestack
,您还可以这样做:

{-# LANGUAGE TemplateHaskell #-}  -- Note the extension

import Control.Lens

data GameState = GameState
    { _gamestack  :: [String]
    , _gamememory ::  String
    }

makeLenses ''GameState
无论您选择哪种方式,一旦我们有了这些镜头,我们就可以编写
push
pop
,只要是一个列表,他们就不关心自己的行为状态:

pop :: State [a] (Maybe a)
pop = do
    s <- get
    case s of
        []   -> return Nothing
        x:xs -> do
            put xs
            return (Just x)

push :: a -> State [a] ()
push d = modify (d:)
请注意,我是如何使用
zoom
来本地化
push
pop
来操作
gamememory
gamestack
字段的<代码>缩放
将镜头移到子字段,然后运行有状态操作,就好像整个状态就是该子字段一样。这很酷,因为现在
push
pop
的可重用性更高,我们不必在其中加入特定的状态数据类型选择

这还使用
=
,设置给定字段。这基本上与:

lens .= x = zoom lens (put x)
要了解更多有关镜头、
(.=)
变焦的信息,您可能需要阅读我写的内容

编辑:根据要求,以下是无镜头版本:

import Control.Monad.State

data GameState = GameState
    { gamestack  :: [String]
    , gamememory ::  String
    }

type NewGameState = State GameState

saveName :: NewGameState ()
saveName = do
    GameState stack memory <- get
    put (GameState (memory:stack) memory)

getName :: NewGameState ()
getName = do
    GameState stack memory <- get
    case stack of
        []   -> put (GameState stack memory)
        x:xs -> put (GameState xs    x     )
import Control.Monad.State
数据游戏状态=游戏状态
{游戏堆栈::[字符串]
,gamememory::String
}
键入NewGameState=状态GameState
saveName::NewGameState()
saveName=do
游戏状态堆栈内存放置(游戏状态xs x)

新游戏状态
是一个糟糕的名字——它根本不是一个新的游戏状态,它是一个携带状态的单子。我刚把它叫做
游戏

pushStack
vs
push
-您给出了名为
pushStack
的签名,然后是名为
push
的函数。挑一个

popStack
中,您有
[]->(0.0,st)
让我们面对现实,
0.0
不是字符串,为什么要尝试返回它?当弹出一个空堆栈时,您是否不知道该怎么做?你用
代替怎么样

saveName和getName你甚至还没有说你想让它们做什么。您似乎接受了其他回答者的解释,因此我们可以使用记录更新语法

最后,这里是一些代码