Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.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
Oop 在函数式编程语言中,如何在函数调用之间保持状态?_Oop_Functional Programming - Fatal编程技术网

Oop 在函数式编程语言中,如何在函数调用之间保持状态?

Oop 在函数式编程语言中,如何在函数调用之间保持状态?,oop,functional-programming,Oop,Functional Programming,我刚刚从面向对象的背景开始涉足功能范式。在函数式编程语言中,状态是如何在函数调用之间持久化的,我对此感到困惑 考虑一个您正在创建的游戏示例,您打算将其发布为库供其他人使用。其他人将使用您的游戏代码作为他们游戏的域,并将其连接到他们自己的UI。使用OO方法,您可能希望客户端使用您的游戏代码,如下所示: main() { Game game = new Game(); while(userHasNotQuit()) { // respond to user inpu

我刚刚从面向对象的背景开始涉足功能范式。在函数式编程语言中,状态是如何在函数调用之间持久化的,我对此感到困惑

考虑一个您正在创建的游戏示例,您打算将其发布为库供其他人使用。其他人将使用您的游戏代码作为他们游戏的域,并将其连接到他们自己的UI。使用OO方法,您可能希望客户端使用您的游戏代码,如下所示:

main() {
    Game game = new Game();

    while(userHasNotQuit()) {
        // respond to user input
        // call some method that mutates the internal data of the game object
            // ex: game.increaseScore();
        // get the data out of the game object
        // display it on screen
    }
}
这里,对客户端隐藏游戏类型的内部数据结构,并且游戏类型可以公开一个公共api,该api准确地定义客户端如何与游戏交互。由于OO访问修饰符,它可以实现数据和函数隐藏

我似乎不知道在这种情况下功能性风格是如何运作的。客户端代码是否需要保存对数据结构的引用并将该数据结构传递给自由函数?比如:

main() {
    GameData gameData = createGame(); // structure of data with no methods.

    while(userHasNotQuit()) {
        // respond to user input
        // call some function that returns a transformed gameData
            // ex: gameData = increaseScore(gameData);
        // get the data out of the game object
        // display it on screen
    }
}

如何实现仅公开定义公共api的某些函数,或仅公开游戏数据结构中的某些数据?

FP不会消除状态,这将使它很难做任何有用的事情。它所回避的是非局部可变状态,因为它破坏了引用透明性

这并不难做到。您只需在命令式版本中获取所有您将访问和更改的状态,并将其放入一个数据结构中,然后在游戏循环的所有迭代中穿行。我想你指的就是这个。下面是一个简单的F#翻译示例,说明如何构建这样一个游戏循环

 let rec loop 
         (exitCondition: UserInputs -> GameState -> bool) 
         (update: UserInputs -> GameState -> GameState) 
         (draw: GameState -> unit) 
         (state: GameState) = 
     let inputs = getUserInputs()
     if exitCondition inputs state
         then ()
         else
             let updated = update inputs state
             draw updated 
             loop exitCondition update draw updated
这是一个高阶函数,你可以给出一个初始状态和一个更新每一步状态的函数,一个绘图函数,它的副作用是在屏幕上绘制游戏的框架,还有一个检查退出条件的函数

这为您提供了一个用于更新游戏状态的定义良好的界面-所有更新都是作为
update
功能的一部分进行的,您可以确保在
exitCondition
draw
中所做的任何操作都不会干扰该功能

至于数据隐藏,这在FP中通常不太重要——因为状态是不可变的,并且函数所做的所有更改在返回值中都是显式的,所以让API的用户访问数据就不用担心了。这并不是说他们可以通过随意变异来破坏内部的东西。但是,您可以将该状态拆分为两个单独的部分,并且只将“public”部分传递给update函数(将其改为
update:UserInputs->PublicGameState->PublicGameState

虽然上面的例子相当简单,但它表明,就表达能力而言,您可以用FP语言编写游戏。一本关于在游戏中应用类似函数方法的好书


另一个主题是函数式反应式编程,它有一点不同的味道。Yan Cui谈到用ELM编写一个简单的游戏,你可能也会觉得很有趣。

作为一个非常简单的例子,你可以做如下事情

//伪代码
函数main(){
函数循环(游戏状态){
//循环中的任何东西
// ...
//循环新状态
循环({a:(gameState.a+1)});//{a:2},{a:3},{a:4}。。。
}
//用某种状态初始化
循环({a:1});
}

也看到

下面是他们文档中的Haskell示例

演示标准
Control.Monad.State Monad
使用的简单示例。这是一个简单的字符串解析算法

模块状态游戏在哪里
进口控制单体状态
--状态单子的示例使用
--传递字典{a,b,c}的字符串
--游戏是从字符串中产生一个数字。
--默认情况下,游戏处于关闭状态,C切换
--比赛时断时续。A'给出+1,b给出-1。
--例如
--“ab”=0
--‘ca’=1
--“cabca”=0
--状态=游戏开启或关闭&当前分数
--=(布尔,整数)
类型GameValue=Int
类型GameState=(Bool,Int)
playGame::String->状态GameState GameValue
玩游戏
(放在,得分-1)
‘c’->放(不放,得分)
_->放(上,得分)
游戏xs
startState=(False,0)
main=打印$evalState(游戏“abcaaaccbbcabbbab”)开始状态

您的示例假定在游戏对象之外存在某种全局游戏数据。这与函数式编程完全相反。“修正”会让你的例子变得枯燥无味,缺乏信息;但同时,在许多方面,更好:

main() {
    GameState gameState = createGame();

    while(gamestate.userHasNotQuit()) {
        // respond to user input
        // call some function that transforms gameData
            // ex: gameData.increaseScore();
        // make the gameData object
        // display the game on screen
    }
}

事实上,在OOP世界中,这可能也是一种更好的方法。游戏状态是程序所操纵的,因此这个更改的最后一步就是调用
gameData.main()
而不是让外部程序了解其内部或状态变化。

函数式编程语言的基本要点是没有状态。@神秘性你是说函数式编程不适用于具有状态的游戏或软件吗?请详细说明。@AlexeyFrunze-是的,准确地说。如果您需要跟踪状态,并且需要对事件做出反应,那么函数式编程将不适用。函数式编程不使用状态,这意味着函数的输出完全依赖于输入,对于相同的输入,您会得到相同的输出。函数程序可以更容易地进行推理,并且通常没有那么多错误。状态常常导致错误。@谜:似乎你还没有听说过函数式反应式编程:-)顺便说一句,函数式编程同样适用于需要状态的软件。这些程序都是关于状态的-好处是状态是显式的,而不是隐式的。@Enigmativity,但这并不意味着FP不适用于