有时需要执行一些复杂的例程来检索或保存正在处理的数据。在这种情况下,需要将数据生成和数据处理逻辑分开。常见的方法是使用类似迭代的功能。有很多不错的库:管道、导管等。在大多数情况下,它们会做这些事情。但是据我所知,它们(可能除了管道)受到处理顺序的限制。
但是考虑一个日志查看器的例子:人类可能希望随机地来回走动。他也可以放大和缩小。我担心迭代者在这里无能为力。
一个简单的解决方案可能如下所示:
-- True is for 'right', 'up', etc. and vice versa
type Direction = Bool
class Frame (f :: * -> *) where
type Dimension f :: *
type Origin f :: * -> *
grow', shrink' move' :: Monad m => Dimension f -> Direction -> f a -> m (f a)
move' dim dir f = grow' dim dir f >>= shrink' dim (not dir)
liftF' :: (Origin f a -> b) -> f a -> b
class Frame f => MFrame f where
liftMF' :: (Origin f a -> (b, Origin f a)) -> f a -> (b, f a)
-- Example instance: infinite stream.
data LF a = LF [a] [a] [a]
instance Frame LF where
type Dimension LF = () -- We have only one dimension to move in...
type Origin LF = [] -- User see piece of stream as a plain list
liftF' f (LF _ m _) = f m
grow' () True (LF l m (h:r)) = return $ LF l (m++[h]) r
...
然后可以将其包装到 StateT 中,依此类推。所以,问题:
0)我是否完全错过了迭代的要点,它们在这里适用?
1)我只是重新发明了一个众所周知的轮子吗?
2) 很明显,增长和收缩操作非常无效,因为它们的复杂性与帧大小成正比。有没有更好的方法来延长这样的拉链?