【问题标题】:Making game with pure functional language用纯函数式语言制作游戏
【发布时间】:2020-12-07 08:16:53
【问题描述】:

为了我的函数式编程技能,我正在尝试使用 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 示例)?

【问题讨论】:

    标签: haskell functional-programming f#


    【解决方案1】:

    如果您只想替换ComplicatedGame 值中的c(我们称之为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 中那么好。

    当您使用复制和更新表达式时,您不会重建整个宇宙。值是不可变的,因此您不接触的数据结构会被重用。它非常有效,但不太可能像突变一样那样有效(尽管编译器优化可能会让你到达那里)。

    【讨论】:

    • 在 Haskell 中,相当于 let g1 = g { starSystems = {- change here -}}
    猜你喜欢
    • 2010-12-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-12
    • 1970-01-01
    • 1970-01-01
    • 2023-03-04
    • 1970-01-01
    相关资源
    最近更新 更多