使用Haskell镜头库时,我遇到了以下问题。
让我使用Gabriel Gonzalez撰写的"Program imperatively using Haskell lenses"博客文章中的例子。
{-# LANGUAGE TemplateHaskell #-}
import Control.Lens
data Game = Game
{ _score :: Int
, _units :: [Unit]
, _boss :: Unit
} deriving (Show)
data Unit = Unit
{ _health :: Int
, _position :: Point
} deriving (Show)
data Point = Point
{ _x :: Double
, _y :: Double
} deriving (Show)
makeLenses ''Game
makeLenses ''Unit
makeLenses ''Point
这是一个很好的玩具结构。具体来说,这是一个实例化:
gameState :: Game
gameState = Game
{ _score = 0
, _units =
[ Unit
{ _health = 10
, _position = Point { _x = 3.5, _y = 7.0 }
}
, Unit
{ _health = 15
, _position = Point { _x = 1.0, _y = 1.0 }
}
, Unit
{ _health = 8
, _position = Point { _x = 0.0, _y = 2.1 }
}
]
, _boss = Unit
{ _health = 100
, _position = Point { _x = 0.0, _y = 0.0 }
}
}
查询单位的工作方式如下:
gameState ^.. units . traverse . health -- health of all units is [10,15,8]
可以像这样
更改所有单位的运行状况gameState & units . traverse . health .~ 100
这里我被卡住了:假设我想对单位的遍历应用转换,即获得所有单位的健康状况,根据某些规则更改所有单位,并设置它们。例如,如果我想要反转健康列表(在这个例子中不是一个非常有意义的转换),这样的事情应该有效:
gameState & units . traverse . health %~ reverse
但我无法确定使用哪个运营商。
我使用此示例作为指导(排序和替换所有元素< 4)
[2,4,3,5,4,6,1] & partsOf (traverse. filtered (<4)) %~ sort -- is [1,4,2,5,4,6,3]
答案 0 :(得分:3)
对于这种特殊的转变,我认为你正在寻找:
gameState & partsOf (units.traverse.health) %~ reverse
光学:
units.traverse.health
代表_health
内每个Unit
Unit
的遍历(按_units
字段中显示Game
的顺序)。这与镜头(不是遍历!)不同,它关注健康列表[Int]
中的Game
- 为了得到这个,您需要将partsOf
应用于遍历
如果 - 如Control.Lens.Traversal
模块中所述,您可以直接使用遍历 - 您希望遍历结构,使用monadic或applicative side effects(按从左到右的顺序应用)更改其内容。但是,如果您希望将整个列表作为一个整体进行操作并使用常规[Health] -> [Health]
转换,则需要先将遍历转换为partsOf
镜头。