Haskell - 在元组内操作数据

时间:2014-08-08 03:40:15

标签: haskell tuples

我尝试使用haskell模拟跳棋游戏。我得到一个名为checkersState的4元组,我想用几个不同的函数来操作。到目前为止,我有一个函数oneMove,它接收来自checkerState的输入,并应返回修改数据的元组:

输入元组:

    (
    3600,
    "",
    [
    "----------",
    "------r---",
    "----------",
    "----------",
    "---r-r----",
    "------r---",
    "---w---w-w",
    "----------",
    "----------",
    "------w---"
    ],
    (
    49
    ,
    43  
    )
    )

到目前为止,我有类似于下面定义我的函数的东西,但我不确定如何访问元组checkerState中的各个成员。这种方法需要一段时间,一系列被捕获的棋子,棋盘和移动制作,并返回一个时间,一系列被捕获的棋子和棋盘。目前,我想根据主板的状态修改元组中的时间(INT):

    onemove :: (Int,[Char],[[Char]],(Int,Int)) -> (Int,[Char],[[Char]])

提前致谢!

3 个答案:

答案 0 :(得分:7)

您可以使用模式匹配来提取元素,执行需要进行的任何更改,并将它们打包回元组。例如,如果要增加第一个值,可以:

onemove (a,b,c,d) = (a + 1,b,c,d)

如果你发现自己这么做了,你可能会重新考虑使用元组而不是使用数据类型:

data CheckersState = CheckersState { time  :: Int       -- field names are just
                                   , steps :: [Char]    -- guesses; change them
                                   , board :: [[Char]]  -- to something that
                                   , pos   :: (Int, Int)  -- makes sense
                                   } deriving (Eq, Read, Show)

然后您可以使用更方便的语法更新它:

onemove state = state { time = time state + 1 }

如果您想坚持使用元组并且恰好使用lenses,那么还有另一种更新元组的简单方法:

onemove = over _1 (+1)

或者,如果您使用镜头您自己的数据类型(使用适当定义的访问器,如提供的那个),您可以执行类似的操作:

_time :: Lens' CheckersState Int
_time f state = (\newTime -> state { time = newTime }) <$> f (time state)

onemove = over _time (+1)

所以有很多奇特的方法可以做到这一点。但最通用的方式是使用模式匹配。

答案 1 :(得分:1)

正如icktoofay所说,使用元组是代码气味,并且使用命名组件的记录更好。

另外,使用Char(和String)是代码气味。要修复它,请定义一个精确描述您在电路板单元格中所期望的数据类型,例如data Colour = None | Red | Black,但请参阅下一项。

而且,使用Lists也是一种代码气味。您实际上需要type Board = Data.Map.Map Pos ColourData.Map.Map Pos (Maybe Colour')data Colour' = Red | Black

哦,Int也是一种代码味道。您可以定义newtype Row = Row Int ; newtype Col = Col Int ; type Pos = (Row,Col)。对于新类型可能deriving Num,但不清楚,例如,您不希望乘以行数。也许deriving (Eq,Ord,Enum)就足够了,Enum你得到predsucc

(啊 - 这个Pos正在使用一个元组,因此它有点臭?嗯,不,有时允许2元组。)

答案 2 :(得分:0)

使用pattern matching将元组分解为变量。

onemove (i, c, board, (x, y)) = <do something> (i, c, board)

但是,您应该为电路板定义一个单独的数据结构,以明确您的意图。我不知道前两个值的含义。请参阅:http://learnyouahaskell.com/making-our-own-types-and-typeclasses