【问题标题】:What is the type of apomorphism specific to list and how is it implemented?什么是特定于 list 的同构类型,它是如何实现的?
【发布时间】:2019-10-12 06:48:26
【问题描述】:

我正在学习递归方案,事实证明,针对列表类型实现它们对我很有帮助。但是,我被困在了同胚上。

这是我最近发现的关于 apo 的 tails 的实现:

import Data.Functor.Foldable

tailsApo :: [a] -> [[a]]
tailsApo = apo coalgTails
    where
    coalgTails = \case
        [] -> Cons [] (Left [])
        li@(_:xs) -> Cons li (Right xs)

很遗憾,我无法使用 GHCi 导入 Data.Functor.Foldable,因为我收到了未找到包的错误。另一项搜索显示了这种特定于列表的 apo 实现:

apoList :: ([b] -> Maybe (a, Either [b] [a])) -> [b] -> [a]
apoList f b = case f b of
    Nothing -> []
    Just (x, Left c)  -> x : apoL f c
    Just (x, Right e) -> x : e

显然,apoList 的第一个参数与tailsApo 不匹配。我会将类型解释为apoList :: ([b] -> Either (a, b) [a])) -> [b] -> [a]

似乎没有更多关于此主题的适合初学者的信息。感谢您的帮助。

【问题讨论】:

  • 你可以使用cabal install recursion-schemes安装包。

标签: haskell recursion-schemes unfold


【解决方案1】:

The type is

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]we'll have

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)
}                           }

【讨论】:

  • s@(_:xs)是什么意思?
  • 它被称为“as-pattern”。 s指整体,与(_:xs)同时匹配。
  • 这两个答案都非常有帮助,我希望我能以一种共享模式接受这两个答案。在某些情况下,接受不应该是二元的。
【解决方案2】:

Data.Functor.Foldablerecursion-schemes 包提供。 apo的类型有:

apo :: Corecursive t => (a -> Base t (Either t a)) -> a -> t 

这里,t 是展开生成的结构,Base t 是它的基本函子。从广义上讲,基本函子代表了递归结构的一层,其想法是,如果我们将它无限地嵌套在自身内部,我们将得到一个与整个结构等效的类型——事实上,这正是来自 @ 的 Fix 987654328@ 可以。 (在元注释中,这里似乎没有专门针对 recursion-schemes 中的 Base 的问答;有一个可能很有用。)

Base 对于列表是:

data ListF a b = Nil | Cons a b

所以apo 专注于:

apo @[_] :: (b -> ListF a (Either [a] b)) -> b -> [a]

如果我们想在不使用 recursion-scheme 基础架构的情况下编写它,我们可以使用 ListF a bMaybe (a, b) 同构的事实:

Nil     | Cons  a  b
Nothing | Just (a, b)

Maybe (a, b)而言,签名将变为:

apoList :: (b -> Maybe (a, Either [a] b)) -> b -> [a]

在代数(即apo 的函数参数)中,Nothing(或Nil,在 recursion-schemes 版本中)信号列表的生成应该是通过用空尾巴盖住它来停止。这就是为什么您仍然需要Maybe,即使您还使用Either 以其他方式短路展开。

这个apoList 的实现很像你问题中的那个,除了这个签名不会将种子(b 类型)限制为一个列表,并翻转LeftRight(因此Left 发出短路信号):

apoList :: (b -> Maybe (a, Either [a] b)) -> b -> [a]
apoList f b = case f b of
    Nothing -> []
    Just (x, Left e) -> x : e
    Just (x, Right c) -> x : apoList f c

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-11-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多