query_string
然后我 {
"person_name" : "John Bradshaw",
"name": "Abraham",
"office": {
"name":"deVilliers"
}
},
{
"person_name" : "Abraham",
"name": "deVilliers",
"office": {
"name":"blabla"
}
}
了解上述数据类型。
游戏退出条件是玩家手中的所有牌都是后退。 所以在我的Game StateT monad中,我访问了所有的CardStatus并测试它们。由于我是Lens的新手,我想知道写这篇文章的优雅方式是什么。 在镜头操作员的森林中有点迷失。
答案 0 :(得分:3)
模块Control.Lens.Fold
有许多用于测试镜头/折叠/遍历目标的组合器:has
(用于检查棱镜是否匹配),anyOf
,noneOf
, allOf
...
在您的示例中(假设CardStatus
也有generated the prisms),我们可以执行以下操作:
endGame :: Game -> Bool
endGame = anyOf (players.folded) (allOf (cards.folded.status) (has _Back))
另外,要找到哪些玩家获胜,我们可以使用filtered
:
winners :: Fold Game Player
winners = players.folded.filtered (allOf (cards.folded.status) (has _Back))
这些功能类似于典型的列表功能,但可以直接应用于折叠,因此它们不会像镜头世界一样将你拉出来。例如,我们可以继续使用另一个winners
撰写Fold
。
答案 1 :(得分:2)
所以你想要一个能够告诉你所有牌都是Back
的镜片。道德上
allBack :: Getter Player Bool
这显然是
的形式allBack = cards . _
...不要再进一步了,请问GHC是否有任何意义:
$ ghc wtmpf-file11136.hs
wtmpf-file11136.hs:26:19: error:
• Found hole: _ :: (Bool -> f Bool) -> [Card] -> f [Card]
好吧,听起来很明智。那个签名看起来很可疑是好老的
traverse :: (a -> f b) -> [a] -> f [b]
......这确实是整个Van Laarhoven镜片形式主义的原型,并且在构建实际镜片组合链时经常是有用的。显然,我们仍然需要关注更多,但首先要注意:
allBack = cards . traverse . _
给
wtmpf-file11136.hs:26:19: error:
• Could not deduce (Applicative f) arising from a use of ‘traverse’
...
wtmpf-file11136.hs:26:30: error:
• Found hole: _ :: (Bool -> f Bool) -> Card -> f Card
好的,这里的问题是Getter
应该立即专注于单个元素。但实际上,我们首先需要检查多个元素以将( fold )压缩为单个Bool
。这意味着我们需要将签名从Getter
更改为Fold
(引擎盖提供Applicative
约束):
allBack :: Fold Player Bool
allBack = cards . traverse . _
• Found hole: _ :: (Bool -> f Bool) -> Card -> f Card
...
• No instance for (Monoid Bool) arising from a use of ‘allBack’
好的,这是有道理的 - 我们指定我们想要以某种方式减少列表,但有一种方法可以减少列表中的bool。在我们的例子中,我们希望它们全部为真,即我们需要从Bool
切换到All
monoid:
import Data.Monoid (All(..))
allBack :: Fold Player All
allBack = cards . traverse . _
wtmpf-file11136.hs:26:30: error:
• Found hole: _ :: (All -> f All) -> Card -> f Card
好的,那看起来不错。现在我们需要指定我们要检查的卡的属性。好吧,关于它的状态:
allBack = cards . traverse . status . _
• Found hole: _ :: (All -> f All) -> CardStatus -> f CardStatus
此时我们现在需要做出决定,即我们需要投入 prism 。有人可能会认为它是_Back
棱镜,但实际上这代表了“无聊”的情况。我们想要触发失败的情况是_Face
:
allBack = cards . traverse . status . _Face . _
• Found hole: _ :: (All -> f All) -> () -> f ()
在此,所有尚未完成的事情是宣布此_Face
是失败案例:
allBack = cards . traverse . status . _Face . like (All False)
虽然正如Willem Van Onsem评论说纯粹的镜头在这里并不是最佳选择。将此作为函数写成更为明智,danidiaz' suggestion达到了良好的平衡。