使用镜头测试地图成员资格

Testing for map membership with lenses

使用镜头检查状态图是否有键的惯用方法是什么?这是我目前的尝试:

module Foo where

import Control.Lens
import Data.Map
import Control.Monad.State
import Data.Maybe (isJust)

check :: Int -> StateT (Map Int Int) IO ()
check k = do
  present <- use $ at k.to isJust
  unless present $ lift $ putStrLn "Not present!"

这可行,但 to isJust 部分感觉有点笨拙...

对于这种特殊情况,请保持简单,不要使用 lens:

present <- gets (member k)

如果您仍然要使用 lens,例如需要通过一些字段遍历进入状态才能得到地图,使用uses:

present <- uses (field1.field2) (member k)

要根据 uses 编写第一个动作,请使用恒等光学 id:

present <- uses id (member k)

但我不建议无偿这样做。

我只想补充一下,查看某个键是否在地图中 == 检查对该键的遍历 是否具有 目标。

has (ix 5) :: (Ixed s, Num (Index s)) => s -> Bool

use (to $ has $ ix 5) :: 
  (MonadState s m, Ixed s, Num (Index s)) => m Bool

uses id (has $ ix 5) :: 
  (MonadState s m, Ixed s, Num (Index s)) => m Bool

但很明显 none 这些都是非常合适的镜头。查看源码,

use = gets . view

所以我们可以这样写,

hasUse :: (MonadState s m) => Getting Any s a -> m Bool
hasUse = gets . has

:t hasUse $ ix 5
hasUse $ ix 5 :: 
  (MonadState s m, Ixed s, Num (Index s)) => m Bool

我发现的另一种说明方式,

Any present <- uses (ix 5) (const $ Any True)