也许不是镜头,而是拉链?
data ListZipper a = LZ { left :: [a], focus :: a, right :: [a] }
listToListZipper :: [a] -> Maybe (ListZipper a)
listToListZipper (a:as) = Just $ LZ [] a as
listToListZipper [] = Nothing
modifyFocus :: (a -> a) -> ListZipper a -> ListZipper a
modifyFocus f z = z { focus = f $ focus z }
goRight :: ListZipper a -> Maybe (ListZipper a)
goRight (LZ ls l (a:rs)) = Just $ LZ (l:ls) a rs
goRight _ = Nothing
goLeft :: ListZipper a -> Maybe (ListZipper a)
goLeft (LZ (a:ls) r rs) = Just $ LZ ls a (r:rs)
goLeft _ = Nothing
listZipperToList :: ListZipper a -> [a]
listZipperToList (LZ ls a rs) = reverse ls ++ a:rs
访问所需的元素很容易(使用modifyFocus
),您可以使您的choose
choose :: [a] -> (a -> String) -> MaybeT IO (ListZipper a)
choose as f = do
i <- lift $ choose' as f
let z = listToListZipper as
MaybeT . return $ goto i z
where choose' :: [a] -> (a -> String) -> IO Int
choose' = ...
goto :: Int -> ListZipper a -> Maybe (ListZipper a)
goto 0 z = return z
goto n z = do
z' <- goRight z
goto (n-1) z'
甚至
forceValidChoice :: [a] -> (a -> String) -> IO (ListZipper a)
forceValidChoice as f = do
mz <- runMaybeT $ choose as f
maybe (forceValidChoice as f) return mz