类型是
apo :: (a -> Base t (Either t a )) -- g :: a -> Base t r
-> a -> t
apo g a = rec a where -- rec = apo g :: a -> t
rec = embed . fmap (either id rec) . g
{-
type family Base t :: * -> *
embed :: Base t t -> t
fmap (either id rec) :: Base t r -> Base t t
either id rec :: r -> t r ~ Either t a
g :: a -> Base t r r ~ Either t a
rec = apo g :: a -> t
-}
这里a
是种子。因为t ~ [b]
我们会有
type instance Base [b] = ListF b
data ListF b r = Nil | Cons b r
Base t (Either t a) ~ ListF b (Either [b] a)
~ Maybe (b, Either [b] a)
所以总的来说会
apoList :: (a -> Maybe (b, Either [b] a)) -> a -> [b]
apoList coalg a = case coalg a of
Nothing -> [] -- (embed Nil ) -- either
Just (b, Left bs) -> b : bs -- no more seed, no more steps to do! -- id $ bs
Just (b, Right a) -> b : apoList coalg a -- new seed, go on! -- apo g $ a
-- ^^^^^ (embed (Cons b bs))
所以
apoTails :: [a] -> [[a]] -- [[a]] ~ [b], b ~ [a]
apoTails = apoList tailsCoalg
where
-- tailsCoalg :: [a] -> Maybe ([a], Either [[a]] [a])
tailsCoalg [] = Just ([], Left [])
tailsCoalg s@(_:xs) = Just (s, Right xs)
编辑:更apoList
简单的类型代数,
apoListE :: (a -> Either [b] (b, a)) -> a -> [b]
apoListE coalg a = case coalg a of
Left bs -> bs -- final tail, whether empty or non-empty
Right (b, a) -> b : apoListE coalg a -- new element and seed, go on!
似乎更容易使用:
apoTailsE :: [a] -> [[a]]
apoTailsE = apoListE tailsCoalgE
where
-- tailsCoalgE :: [a] -> Either [[a]] ([a], [a])
tailsCoalgE [] = Left [[]]
tailsCoalgE s@(_:xs) = Right (s, xs)
看起来这两种类型是等价的:
type instance Base [b] = ListF b
data ListF b r = Nil | Cons b r
Base t (Either t a) ~ ListF b (Either [b] a)
~ Maybe (b, Either [b] a)
~ Either [b] (b, a)
--------------------------------------------------------------------
Maybe (b, Either [b] a) ~ Either [b] (b, a)
{ Nothing, ~ { Left [],
Just (b, Left bs), Left (b:bs),
Just (b, Right a) Right (b, a)
} }