簡體   English   中英

“Nil”帶有值的列表?

[英]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 (和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 ,因為我們知道每個有限的LWE必須只包含一個end元素,我們可以通過為它設置一個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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM