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

Haskell中泛型多态ADT的函数实例?

郤旭东
2023-03-14

当涉及到将类别理论应用于泛型编程时,Haskell做得非常好,例如recursion-schemes这样的库。但是,我不确定的一点是如何为多态类型创建泛型函数实例。

如果您有一个多态类型,比如列表或树,您可以创建一个from(Hask×Hask)到Hask的函数来表示它们。例如:

data ListF a b = NilF | ConsF a b  -- L(A,B) = 1+A×B
data TreeF a b = EmptyF | NodeF a b b -- T(A,B) = 1+A×B×B
newtype Fix f = Fix { unFix :: f (Fix f) }
type List a = Fix (ListF a)
type Tree a = Fix (TreeF a)

我试图找出是否有一种方法可以使这些类型(固定点)成为functor的一个通用实例,但我不确定如何实现。到目前为止,我遇到了以下两个问题:

1)首先,必须有一种方法来定义任何多态固定点上的泛型GMAP。知道像listftreef这样的类型是双函数,到目前为止我已经知道了以下内容:

{-# LANGUAGE ScopedTypeVariables #-}
import Data.Bifunctor

newtype Fix f = Fix { unFix :: f (Fix f) }

cata :: Functor f => (f a -> a) -> Fix f -> a
cata f = f . fmap (cata f) . unFix

-- To explicitly use inF as the initial algebra
inF :: f (Fix f) -> Fix f
inF = Fix

gmap :: forall a b f. Bifunctor f => (a -> b) -> Fix (f a) -> Fix (f b)
gmap f = cata alg
    where
        alg :: f a (Fix (f b)) -> Fix (f b)
        alg = inF . bimap f id

在Haskell中,这给了我以下错误:不能从上下文(Bifunctor f)中推导(Functor(f a))。

2)即使可以定义上面的泛型GMAP,我也不知道是否可以创建一个泛型fmap=gmap函数实例,该实例具有fmap=gmap,并且可以立即同时处理上面的listtree类型(以及以类似方式定义的任何其他类型)。这可能吗?

如果是这样的话,是否也可以使其与递归方案兼容?

共有1个答案

黄聪
2023-03-14

如果你现在愿意接受你在处理双截止符,你可以说

cata :: Bifunctor f => (f a r -> r) -> Fix (f a) -> r
cata f = f . bimap id (cata f) . unFix

后来呢

gmap :: forall a b f. Bifunctor f => (a -> b) -> Fix (f a) -> Fix (f b)
gmap f = cata alg
    where
        alg :: f a (Fix (f b)) -> Fix (f b)
        alg = inF . bimap f id

(在GMAP中,我刚刚重新安排了class约束,以使作用域类型变量能够工作。)

gmap :: forall a b f. (Bifunctor f, Functor (f a)) => (a -> b) -> Fix (f a) -> Fix (f b)
gmap f = cata alg
    where
        alg :: f a (Fix (f b)) -> Fix (f b)
        alg = inF . bimap f id
instance ... => Functor (\ x -> Fix (f x))

[您可能也有兴趣阅读http://www.andres-loeh.de/indexedfunctors/以获得更通用的方法。]

 类似资料:
  • 我想实现一个简单的排序函数,排序列表并返回排序列表(非常容易!)。所以我写了这个 问题是,当我试图对一个简单的列表排序时,它会给我带来这样的错误 那有什么问题?! 提前感谢:)))

  • 问题内容: 我正在学习中,文档和交互式课程说,空可以容纳任何类型,因为它不需要其他实现的方法。 举个例子: …将打印出来… 因此,我想我的问题是这是实现通用函数的方法,还是还有另一种更合适的方法来实现它们。 问题答案: Go范式通常是通过在非空接口中实现行为来避免这种情况。例如,假设您要打印特定于类型的格式的内容: 或者,您可以为知道如何进行字符串自身设置的接口定义一个接口(该接口在库中以形式存在

  • 我现在在学习哈斯克尔。但我正在为“类型”而挣扎。 例如,函数的类型是

  • 同样的规则也可以适用于函数:在使用前给出 <T> 后,类型 T 就变成了泛型。 使用泛型函数有时需要显式地指明类型参量。这种可能的情况包括,调用返回类型是泛型的函数,或者编译器没有足够的信息来推导类型参量。 函数调用使用显式指定的类型参量,如下所示: fun::<A, B, ...>(). struct A; // 具体类型 `A`。 struct S(A); //

  • 我试图编写一个函数来返回

  • 我想出了这两个: 我的例子正确地说明了这个练习吗? 给定两个参数: null null 我在SO上看到了一些类似的问题(比如,这个问题),这个问题几乎是我要找的,但不完全是(我只是在找函数的例子,没有别的--没有应用性,没有单子)。