[英]A list whose “Nil” carries a value?
一些標准的Haskell庫是否定義了這樣的數據類型
data ListWithEnd e a = Cons a (ListWithEnd e a)
| End e
這是一個列表,其終止元素帶有指定類型的值?
因此ListWithEnd ()
與[]
同構,而ListWithEnd Void
與無限流同構。 或者,從不同的角度來看, ListWithEnd ea
非常接近ConduitM () 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 :>
我們可以在end元素上進行映射,折疊和遍歷:
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
(和Bifunctor
和Bifoldable
),那將是很好的,因為那時我們可以以更通用和原則的方式訪問列表元素。 為此我們肯定需要一個新類型:
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並在幾行代碼中編寫Applicative
, Monad
和Bitraversable
實例。 或者,我們可以使用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
,因為我們知道每個有限的LWE
必須只包含一個end元素,我們可以通過為它設置一個Lens
(而不是Traversal
或Prism
)來明確這一點。
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
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.