"Nil"具有值的列表?



某些标准Haskell库是否定义了类似的数据类型

data ListWithEnd e a = Cons a (ListWithEnd e a)
                     | End e

这是一个列表,其终止元素携带指定类型的值?

因此ListWithEnd ()同构于[]ListWithEnd Void同构于无限流。或者,从不同的角度来看,ListWithEnd e aConduitM () a Identity e非常接近。。

我们可以如下定义ListWithEnd

import Control.Monad.Free
type LWE a e = Free ((,) a) e

我们通常期望抽象或通用表示应该以样板的整体减少来奖励我们。让我们看看这个表示为我们提供了什么。

在任何情况下,我们都将为cons情况定义一个模式同义词:

{-# LANGUAGE PatternSynonyms #-}
pattern x :> xs = Free (x, xs)
infixr 5 :>

我们可以绘制、折叠和遍历结束元素:

fmap (+1) (0 :> Pure 0) == (0 :> Pure 1)
traverse print (0 :> Pure 1) -- prints 1

Applicative实例为我们提供了非常简洁的连接:

xs = 1 :> 2 :> Pure 10
ys = 3 :> 4 :> Pure 20
xs *> ys          == 1 :> 2 :> 3 :> 4 :> Pure 20 -- use right end
xs <* ys          == 1 :> 2 :> 3 :> 4 :> Pure 10 -- use left end
(+) <$> xs <*> ys == 1 :> 2 :> 3 :> 4 :> Pure 30 -- combine ends

我们可以在列表元素上进行映射,如果有点扭曲的话:

import Data.Bifunctor -- included in base-4.8!
hoistFree (first (+10)) xs == 11 :> 12 :> Pure 10

当然,我们可以使用iter

iter (uncurry (+)) (0 <$ xs) == 3 -- sum list elements

如果LWE可以是Bitraversable(以及BifunctorBifoldable),那就太好了,因为这样我们就可以以更通用和更有原则的方式访问列表元素。为此,我们肯定需要一种新的类型:

newtype LWE a e = LWE (Free ((,) a) e) deriving (lots of things)
instance Bifunctor LWE where bimap = bimapDefault
instance Bifoldable LWE where bifoldMap = bifoldMapDefault
instance Bitraversable LWE where bitraverse = ...

但在这一点上,我们可能会考虑只编写简单的ADT,并在几行代码中编写ApplicativeMonadBitraversable实例。或者,我们可以使用lens并为列表元素编写Traversal

import Control.Lens
elems :: Traversal (LWE a e) (LWE b e) a b
elems f (Pure e)  = pure (Pure e)
elems f (x :> xs) = (:>) <$> f x <*> elems f xs

沿着这条线进一步思考,我们应该为结束元素制作一个Lens。这比一般的Free接口有点好处,因为我们知道每个有限的LWE必须只包含一个端元素,并且我们可以通过为它设置Lens(而不是TraversalPrism)来明确这一点。

end :: Lens (LWE a e) (LWE a e') e e'
end f (Pure e)  = Pure <$> f e
end f (x :> xs) = (x :>) <$> end f xs

相关内容

  • 没有找到相关文章

最新更新