Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/10.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中的typeclass表示游戏状态_Haskell_Typeclass - Fatal编程技术网

用Haskell中的typeclass表示游戏状态

用Haskell中的typeclass表示游戏状态,haskell,typeclass,Haskell,Typeclass,我正在实现一些功能来搜索游戏树,以供自己娱乐。例如,一个这样的函数将执行算法。这些函数使用两种对象: 游戏状态,例如棋盘上棋子的位置、下一个要移动的玩家等 移动,例如“典当e2到e5” 我的目标是拥有适用于不同游戏的搜索功能,因此我将游戏特定知识作为助手功能传递,如: 从给定游戏状态生成所有可能的移动 给定一个状态和一个移动,将移动应用于该状态以获得结果状态 看看这是否是一个胜利的位置 等等 这样,我的搜索功能确实不是游戏专用的,但解决方案仍然感觉不正确。这也使得我的参数列表相当长: --

我正在实现一些功能来搜索游戏树,以供自己娱乐。例如,一个这样的函数将执行算法。这些函数使用两种对象:

  • 游戏状态,例如棋盘上棋子的位置、下一个要移动的玩家等
  • 移动,例如“典当e2到e5”
  • 我的目标是拥有适用于不同游戏的搜索功能,因此我将游戏特定知识作为助手功能传递,如:

    • 从给定游戏状态生成所有可能的移动
    • 给定一个状态和一个移动,将移动应用于该状态以获得结果状态
    • 看看这是否是一个胜利的位置
    • 等等
    这样,我的搜索功能确实不是游戏专用的,但解决方案仍然感觉不正确。这也使得我的参数列表相当长:

    -- Given a game state find the best next move
    bestMove :: s -> (s -> [m]) -> (s -> m -> s) -> m    -- more parameters in my real code
    bestMove currentState possibleMoves applyMove = ...
    
    问题: 我可以用TypeClass替换这些助手函数吗?我在寻找与此类似的东西:

    class Move m where
      apply :: State s => s -> m -> s
    
    class State s where
      possibleMoves :: Move m => s -> [m]
    
    bestMove :: State s => Move m => s -> m
    bestMove currentState = ... -- e.g. = head $ possibleMoves state
    
    问题是
    State
    的任何实例都只能与
    Move
    的一个特定实例一起工作,反之亦然:

    {-# LANGUAGE InstanceSigs #-} 
    
    data ChessState = ...
    data ChessMove  = ...
    
    instance Move ChessMove where
      apply :: ChessState -> ChessMove -> ChessState
      apply s m = ...
    
    apply
    的类型签名当然是错误的。应该是

    apply :: S s => s -> ChessMove -> s
    
    但是我确实需要特定于
    ChessState
    的属性,以便创建
    ChessMove


    我的整个想法是完全错误的,还是有办法对
    ChessState
    ChessMove
    之间的关系进行编码?我在这方面取得了一些进展,但看起来仍然不像我希望的那样。

    首先,如果你可以在没有类型类的情况下做一些事情,那么最好远离它们。您始终可以为特定应用程序制作一个更简单的包装器,特别是在适当翻转参数的情况下:

    bestMove :: (s -> [m]) -> (m -> s -> s) -> s -> m
    
    bestChessMove :: ChessState -> ChessMove
    bestChessMove = bestMove possibleChessMoves applyChessMove
    
    也就是说,我并不认为你所设想的类是不可感知的(不像很多人想挤进Haskell的OO类…)。您的思路非常正确,它应该是一个多内存类:

    {-# LANGUAGE MultiParamTypeClasses #-} 
    
    class MoveState m s where
      apply :: m -> s -> s
      possibleMoves :: s -> [m]
    
    instance MoveState ChessMove ChessState where
      apply = ...
      possibleMoves = ...
    
    然后

    事实上,该类的通用性远远超过了它的意义:对于任何给定的状态类型,您可能只有一种移动类型。表达这一点的一种方式是a
    |s->m
    ;我通常倾向于将
    Move
    类型简单化为state类的“属性”:

    {-# LANGUAGE TypeFamilies #-} 
    
    class GameState s where
      type Move s :: *
      apply :: Move s -> s -> s
      possibleMoves :: s -> [Move s]
    

    首先,如果您可以在没有类型类的情况下做一些事情,那么最好远离它们。您始终可以为特定应用程序制作一个更简单的包装器,特别是在适当翻转参数的情况下:

    bestMove :: (s -> [m]) -> (m -> s -> s) -> s -> m
    
    bestChessMove :: ChessState -> ChessMove
    bestChessMove = bestMove possibleChessMoves applyChessMove
    
    也就是说,我并不认为你所设想的类是不可感知的(不像很多人想挤进Haskell的OO类…)。您的思路非常正确,它应该是一个多内存类:

    {-# LANGUAGE MultiParamTypeClasses #-} 
    
    class MoveState m s where
      apply :: m -> s -> s
      possibleMoves :: s -> [m]
    
    instance MoveState ChessMove ChessState where
      apply = ...
      possibleMoves = ...
    
    然后

    事实上,该类的通用性远远超过了它的意义:对于任何给定的状态类型,您可能只有一种移动类型。表达这一点的一种方式是a
    |s->m
    ;我通常倾向于将
    Move
    类型简单化为state类的“属性”:

    {-# LANGUAGE TypeFamilies #-} 
    
    class GameState s where
      type Move s :: *
      apply :: Move s -> s -> s
      possibleMoves :: s -> [Move s]
    

    你可以考虑只通过整个游戏树:

    data GameTree m s = GameTree s [(m, GameTree m s)]
    
    bestMove :: GameTree m s -> (s -> Int) -> Maybe m
    bestMove gameTree evaluateState = ...
    

    依靠懒惰只扩展你实际观察到的游戏树的部分。

    < P>你可以考虑在整个游戏树中通过:

    data GameTree m s = GameTree s [(m, GameTree m s)]
    
    bestMove :: GameTree m s -> (s -> Int) -> Maybe m
    bestMove gameTree evaluateState = ...
    

    依靠懒惰只扩展游戏树中你实际看到的部分。

    我很难在这个答案和我接受的答案之间做出决定。我觉得这个答案描述了一个更好的解决方案,但对于从不同背景遇到这个问题的人来说可能没有那么有用。我很难在这个答案和我接受的答案之间做出决定。我觉得这个答案描述了一个更好的解决方案,但对于从不同背景遇到这个问题的人来说可能没有那么有用。