当前位置: 首页 > 知识库问答 >
问题:

如何使用具有Fix类型的Functor实例

骆鸿运
2023-03-14
{-# LANGUAGE GADTs, DataKinds #-}

data ListF :: * -> * -> * where
  Nil  ::           List a b
  Cons :: a -> b -> List a b
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

共有1个答案

全流觞
2023-03-14

用双截断子的不动点构造递归函子是正确的,因为1+1=2。列表节点结构是一个容器,包含两种子结构:“元素”和“子列表”。

麻烦的是,我们需要另一个函子的概念(它捕获了一个相当特定的函子种类,尽管它的名称相当通用)来构造一个函子作为一个不动点。然而,我们可以(作为一点特技)转移到一个稍微更一般的函子概念,它在不动点下是闭合的。

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)
    null
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-element或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)
 类似资料:
  • 问题内容: 我对此进行了扩展,应该可以帮助我在上下文之间传输对象: 现在它返回的对象,我应该将其强制转换为我想要的类,如下所示: 有没有办法避免这种无用的转换,如果我从类的对象调用使其返回类型? 问题答案: 更新: 有关更好的解决方案 与如何在NSManagedObjectSwift扩展中如何创建托管对象子类的实例中类似,这可以使用通用的辅助方法来完成: 请注意,我已将返回类型更改为。 并 没有

  • 这是我最想要的代码,它不会编译: 这里的想法是,接口将把ArgumentInterface的实例传递给用户提供的消费者,而SubInterface将传递更具体的ArgumentSubInterface的实例。特别是,我希望用户能够传递一个消费者 天真地说,这似乎应该像写的那样工作:任何被Interface版本接受的论点也将被SubInterface版本接受。然而,Java声称该方法不会覆盖。

  • 问题内容: 我想用Java定义Functor类。这有效: 但是,fmap的返回值应该不是,而是适当的子类。通常,可以使用CRTP对此进行编码,但是由于附加参数,在这里我似乎遇到了麻烦。例如,以下和类似的编码不起作用(“类型参数FInst不在其范围内”): [说明] 对于“适当的子类”,我指的是被称为自身的类的类型。例如,列表是函子,所以我想写一些类似的东西 我知道即使使用给出的第一个定义,我也可以

  • Haskell中的Functor是一种可以映射的不同类型的函数表示。 它是实现多态性的高级概念。 根据Haskell开发人员的说法,所有类型如List,Map,Tree等都是Haskell Functor的实例。 Functor是一个内置类,其函数定义如下 - class Functor f where fmap :: (a -> b) -> f a -> f b 通过这个定义,我们可

  • 我的系统有两种不同类型的消息-类型A和B。每条消息都有不同的结构-类型A包含一个int成员,类型B包含一个double成员。我的系统需要将这两种类型的消息传递给许多业务逻辑线程。减少延迟非常重要,因此我正在研究使用中断器以机械方式将消息从主线程传递到业务逻辑线程。 我的问题是,破坏者只接受环形缓冲区中的一种类型的对象。这是有意义的,因为破坏者预先分配了环形缓冲区中的对象。然而,这也使得通过Disr

  • TypeScript提供一些工具类型来帮助常见的类型转换。这些类型是全局可见的。 目录 Partial<T>,TypeScript 2.1 Readonly<T>,TypeScript 2.1 Record<K,T>,TypeScript 2.1 Pick<T,K>,TypeScript 2.1 Omit<T,K> Exclude<T,U>,TypeScript 2.8 Extract<T,U>,