gpt4 book ai didi

haskell - 如何使用带有 Fix 类型的 Functor 实例

转载 作者:行者123 更新时间:2023-12-01 14:36:13 24 4
gpt4 key购买 nike

假设我想要一个非常通用的 ListF数据类型:

{-# LANGUAGE GADTs, DataKinds #-}

data ListF :: * -> * -> * where
Nil :: List a b
Cons :: a -> b -> List a b

现在我可以将此数据类型与 Data.Fix 一起使用建立一个 f 代数
import qualified Data.Fix as Fx

instance Functor (ListF a :: * -> *) where
fmap f (Cons x y) = Cons x (f y)
fmap _ Nil = Nil

sumOfNums = Fx.cata f (Fx.Fix $ Cons 2 (Fx.Fix $ Cons 3 (Fx.Fix $ Cons 5 (Fx.Fix Nil))))
where
f (Cons x y) = x + y
f Nil = 0

但是我如何使用这种非常通用的数据类型 ListF创建我认为默认的 Functor递归列表的实例(映射列表中的每个值)

我想我可以使用 Bifunctor(映射第一个值,遍历第二个值),但我不知道它如何与 Data.Fix.Fix 一起使用?

最佳答案

通过取双仿函数的固定点来构造递归仿函数是完全正确的,因为 1 + 1 = 2。列表节点结构作为具有 2 种子结构的容器给出:“元素”和“子列表”。

令人不安的是,我们需要一个全新的 Functor 的概念。 (尽管它的名称相当笼统,但它捕获了一种相当特定的仿函数)来构造一个 Functor作为一个固定点。然而,我们可以(作为一个噱头)转向一个稍微更一般的仿函数概念,它在固定点下是封闭的。

type p -:> q = forall i. p i -> q i

class FunctorIx (f :: (i -> *) -> (o -> *)) where
mapIx :: (p -:> q) -> f p -:> f q

这些是索引集上的仿函数,因此这些名称不仅仅是对 Goscinny 和 Uderzo 的无偿敬意。你可以想到 o作为“各种结构”和 i作为“各种子结构”。这是一个示例,基于 1 + 1 = 2 的事实。
data ListF :: (Either () () -> *) -> (() -> *) where
Nil :: ListF p '()
Cons :: p (Left '()) -> p (Right '()) -> ListF p '()

instance FunctorIx ListF where
mapIx f Nil = Nil
mapIx f (Cons a b) = Cons (f a) (f b)

为了利用子结构排序的选择,我们需要一种类型级别的案例分析。我们无法摆脱类型函数,因为
  • 我们需要它被部分应用,这是不允许的;
  • 我们需要在运行时告诉我们存在哪种排序。

  • data Case :: (i -> *) -> (j -> *) -> (Either i j -> *)  where
    CaseL :: p i -> Case p q (Left i)
    CaseR :: q j -> Case p q (Right j)

    caseMap :: (p -:> p') -> (q -:> q') -> Case p q -:> Case p' q'
    caseMap f g (CaseL p) = CaseL (f p)
    caseMap f g (CaseR q) = CaseR (g q)

    现在我们可以获取固定点:
    data Mu :: ((Either i j -> *) -> (j -> *)) ->
    ((i -> *) -> (j -> *)) where
    In :: f (Case p (Mu f p)) j -> Mu f p j

    在每个子结构位置,我们进行案例拆分,看看我们是否应该有一个 p -元素或 Mu f p子结构。我们得到了它的功能性。
    instance FunctorIx f => FunctorIx (Mu f) where
    mapIx f (In fpr) = In (mapIx (caseMap f (mapIx f)) fpr)

    要从这些东西构建列表,我们需要在 * 之间进行权衡。和 () -> * .
    newtype K a i = K {unK :: a}

    type List a = Mu ListF (K a) '()
    pattern NilP :: List a
    pattern NilP = In Nil
    pattern ConsP :: a -> List a -> List a
    pattern ConsP a as = In (Cons (CaseL (K a)) (CaseR as))

    现在,对于列表,我们得到
    map' :: (a -> b) -> List a -> List b
    map' f = mapIx (K . f . unK)

    关于haskell - 如何使用带有 Fix 类型的 Functor 实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45256806/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com