Haskell更新参数

时间:2018-04-27 11:27:53

标签: haskell

我想尝试新的东西,所以我决定把头包裹在Haskell周围。来自主要的C#/ Java背景,我有一个关于更新各种值的问题。我已经设法将其缩小到一个问题。考虑以下功能:

appendHistory :: State -> Action -> State
appendHistory (State gs p1 p2 h) a = State gs p1 p2 (a : h)

这基本上将行动附加到州的历史上。在这种情况下,gsp1p2相当无关紧要,因为我们正在尝试更新h。为了复制它们需要命名的变量(所以我可以在=的右侧使用它们)。我有什么方法可以写appendHistory,以便h得到更新,而无需明确指定gsp1p2

一个选项是让其他函数处理检索和更新状态。 appendHistory现在不必指定其他参数。不是我的最爱,因为我们刚刚将问题转移到了updateHistory。在哈斯克尔:

appendHistory :: State -> Action -> State
appendHistory s a = updateHistory s (a : (history s))

history :: State -> History
history (State _ _ _ h) = h

updateHistory :: State -> History -> State
updateHistory (State s p1 p2 _) h = State s p1 p2 h

另一种方法是使用记录。但我被告知(/读)使用相同名称时可能会发生名称冲突。我想我会有很多字段名为state的记录,所以我暂时一直在避开这些记录。

我想,我想做的就是(非功能性):

void Update(State state, Action action) {
    state.history.append(action);
}

有没有办法在Haskell中很好地做到这一点,而不必为每个data参数写一个'getter'和'setter'?

完整参考:

type History = [Action]
type Deck = [Card]
type Hand = [Card]
type Graveyard = [Card]

data Card = Card -- Still to expand

data PlayerState = PlayerState Hand Deck Graveyard
data GameState = NotStarted | Playing | Finished

data State = State GameState PlayerState PlayerState History

Action只是关于如何变异State的定义。

1 个答案:

答案 0 :(得分:2)

正如melpomene评论的那样,lenses是您问题的现代标准答案。您可以手动定义镜头

{-# LANGUAGE Rank2Types, TypeFamilies #-}
import Control.Lens

gameHistory :: Lens' State History
gameHistory = lens (\(State _ _ _ h) -> h)
                   (\(State gs p1 p2 _) h -> State gs p1 p2 h)

...或让模板Haskell为你做这件事

{-# LANGUAGE TemplateHaskell #-}
data State = State {
        _gameState :: GameState
      , _player₀State, _player₁State :: PlayerState
      , _gameHistory :: History }
makeLenses ''State

自动创建

gameState :: Lens' State GameState
player₀State :: Lens' State GameState
player₁State :: Lens' State GameState
gameHistory :: Lens' State History

有了这样的镜头后,您可以使用operators来调整State个对象:

appendHistory :: Action -> State -> State -- more conventional argument order in Haskell
appendHistory a = gameHistory %~ (a:)