广义的“折叠”或如何一次执行“折叠”和“地图”

时间:2013-07-24 13:06:46

标签: haskell category-theory

(标题道歉,我不能做得更好)

我的问题是找到一些通用结构或"标准"功能执行下一件事:

xmap :: (a -> b) -> f a -> g b

然后,我们不仅可以映射元素,还可以映射整个结构。

一些(不是真实的)例子

xmap id myBinaryTree :: [a]

目前,我必须进行明确的结构转换(典型的fromListtoList)然后

toList . fmap id   -- if source struct has map
fmap id . fromList -- if destination struct has map

(要执行toStructfromStruct我使用fold)。

是否存在某种推广to / from结构的方法? (应该) 功能存在(xmap)?

谢谢!! :)

2 个答案:

答案 0 :(得分:5)

由于fg是仿函数,因此您需要natural transformation(另请参阅You Could Have Defined Natural Transformations)。所以像

这样的转变
f :~> g = forall a. f a -> g a 

需要创建xmap,然后只需

xmap :: (a -> b) -> (f :~> g) -> (f a -> g b)
xmap f n = map f . n

你仍然需要定义(f :~> g)的类型,但没有一般的方法。

答案 1 :(得分:4)

我想添加到tel's answer(我在阅读之后才得到我的想法),在许多情况下,你可以进行与foldMap类似的一般自然变换。如果我们可以使用foldMap,我们知道fFoldable。然后我们需要一些方法来构造g a的元素并将它们组合在一起。我们可以使用Alternative,我们需要它(pureempty<|>),尽管我们也可以为此目的构造一些不太通用的类型类(我们在任何地方都不需要<*>

{-# LANGUAGE TypeOperators, RankNTypes #-}
import Prelude hiding (foldr)
import Control.Applicative
import Data.Foldable

type f :~> g = forall a. f a -> g a

nt :: (Functor f, Foldable f, Alternative g) => f :~> g
nt = foldr ((<|>) . pure) empty

然后使用tel的xmap

xmap :: (a -> b) -> (f :~> g) -> (f a -> g b)
xmap f n = map f . n

我们可以做像

这样的事情
> xmap (+1) nt (Just 1) :: [Int]
[2]