分离数据加载/卸载和处理逻辑

use*_*391 7 haskell haskell-pipes

有时需要执行一些复杂的例程来检索或保存正在处理的数据.在这种情况下,人们想要分离数据生成和数据处理逻辑.常见的方法是使用类似iteratee的功能.有很多不错的图书馆:管道,管道等.在大多数情况下,他们会做这件事.但是AFAIK它们(除了,可能是管道)受到处理顺序的限制.

但考虑一个日志查看器示例:人类可能希望随机来回漫步.他也可以放大和缩小.我担心迭代者在这里无能为力.

一个简单的解决方案可能如下所示:

-- 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
  ...
Run Code Online (Sandbox Code Playgroud)

然后可以将其包装到StateT中,依此类推.所以,问题:

0)我是否完全错过了迭代的重点,它们适用于此?

1)我刚刚重新发明了一个众所周知的车轮吗?

2)很明显,增长和缩小操作非常无效,因为它们的复杂性与帧大小成正比.有没有更好的方法来扩展这样的拉链?

Gab*_*lez 5

你想要镜头,特别是sequenceOf功能.以下是3元组目标加载的示例:

 sequenceOf _2 :: (IO a, IO b, IO c) -> IO (IO a, b, IO c)
Run Code Online (Sandbox Code Playgroud)

sequenceOf将镜头带到包含加载操作的多态字段,运行操作,然后用操作结果替换该字段.sequenceOf只需在要加载的字段中使类型具有多态性,就可以在自己的自定义类型上使用,如下所示:

data Asset a b = Asset
    { _art :: a
    , _sound :: b
    }
Run Code Online (Sandbox Code Playgroud)

...并且还使你的镜头使用完整的四种类型参数(这是它们存在的一个原因):

art :: Lens (Asset a1 b) (Asset a2 b) a1 a2
art k (Asset x y) = fmap (\x' -> Asset x' y) (k x)

sound :: Lens (Asset a b1) (Asset a b2) b1 b2
sound k (Asset x y) = fmap (\y' -> Asset x y') (k y)
Run Code Online (Sandbox Code Playgroud)

...或者您可以使用自动生成镜头makeLenses,它们将足够通用.

然后你可以写:

sequenceOf art :: Asset (IO Art) b -> IO (Asset Art b)
Run Code Online (Sandbox Code Playgroud)

...加载多个资产就像组成Kleisli箭头一样简单::

sequenceOf art >=> sequenceOf sound
    :: Asset (IO Art) (IO Sound) -> IO (Asset Art Sound)
Run Code Online (Sandbox Code Playgroud)

...当然,您可以嵌套资产并组合镜头以达到嵌套资产,一切仍然"正常".

现在你有一个纯Asset类型,你可以使用纯函数处理,所有加载逻辑都被分解为镜头.

我在手机上写了这个,所以可能有几个错误,但我稍后会修复它们.