【问题标题】:Haskell--Manipulating data within a tupleHaskell——在元组中操作数据
【发布时间】:2014-08-08 03:40:15
【问题描述】:

我正在尝试使用 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]])

提前致谢!

【问题讨论】:

  • 您是否考虑过编写data 类型,也许是Record 类型,以便您可以更轻松地访问不同的字段?
  • Haskell 对具有两个以上元素的元组的支持有些有限(除非您使用像镜头这样的额外库),也许部分是为了阻止使用它们,正如其他人所说,使数据类型通常显示更清晰您的类型的预期用途。

标签: haskell tuples


【解决方案1】:

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

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)

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

【讨论】:

  • 很遗憾,数据结构和设计选择都是教授给的。操作完成后,我可以从元组转换为数据类型,然后再转换回元组吗?这对于手头的操作来说可能是多余的。我正在更新问题以添加更多细节,但您的变量实际上大多是正确的。时间数据状态将根据板子和位置移动之间的某些条件进行更新。
  • @Dev:我想你可以在操作之前和之后进行转换,但取决于操作的参与程度,转换的开销可能比直接处理元组更不清晰。
【解决方案2】:

正如 icktoofay 所说,使用元组是一种代码味道,使用命名组件的记录要好得多。

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

而且,使用列表也是一种代码味道。你实际上想要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 元组。)

【讨论】:

    【解决方案3】:

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-18
      • 1970-01-01
      • 1970-01-01
      • 2018-01-18
      • 2021-01-03
      • 1970-01-01
      • 2020-05-02
      • 1970-01-01
      相关资源
      最近更新 更多