用纯功能语言制作游戏

问题描述

为了我的功能编程能力,我正在尝试使用F#构建命令行游戏。借助结构简单的游戏,我可以保持游戏的纯度,例如:

(未经严格测试)

type HangmanGame = HangmanGame [char] string (deriving Show)

runGame :: Game -> IO Game
runGame (Game guessed answer) = do
    guess <- getLine
    -- validate guess
    -- do someting with guess
    runGame (Game guess:guessed answer)

我认为这个简单的类似子手的游戏的主要概念是Game guessed answer已经消失,取而代之的是Game guess:guessed answer。由于游戏只有两个领域,因此以新的价值进行重构非常容易。但是当涉及到...

type ComplicatedGame = Game {
    a :: Int,b :: String,c :: Int,d :: String,...
    z :: String
}

当我只想更改c时,我必须像Game a b newC d ... z那样重建整个游戏价值。

此外,借助类似《太空漫游》游戏系统

type Galaxy = Galaxy {
    name :: String,starSystems :: [StarSystem]
}

type StarSystem = StarSystem {
    name :: String,planets :: Planets
}

type Planet = Planet {
    name :: String,men :: [Human],buildings :: [Building]
}

在单个行星中对men的数量的一次更改将导致Galaxy的整个重建!

由于稍后将使用Unity3d和C#创建UI系统,因此我想使用F#创建核心代码。但是我认为禁止变异将导致上述情况,这不是理想的情况。但我也认为,坚持使用C#会比采用可变性更好,因为可变性不会增加我的函数式编程技能。

请您给我一些建议,以通过函数式编程来创建和处理巨大的数据结构(例如上面的Galaxy示例)。

解决方法

如果您只想替换c值中的ComplicatedGame(我们将其称为cg),则可以使用copy-and-update expression

let c1 = { cg with c = newC }

如果您愿意,可以嵌套这些,尽管确实很尴尬:

let g1 = { g with starSystems = { (* update one planet here...*) } }

(我没有尝试进行编译,因此我可能在上面做了一些错别字。)

在Haskell中不得不编写嵌套的复制和更新表达式的尴尬导致lenses,但是由于F#不支持类型类,因此F#中没有内置的等效项。您可以使用F#手工制作镜头,但它们不如Haskell那样好。

使用复制和更新表达式时,重建整个Universe。值是不可变的,因此可以重用您不接触的数据结构。它非常有效,但不如突变有效(尽管编译器的优化可能会达到目标)。

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...