(标题道歉,我不能做得更好)
我的问题是找到一些通用结构或"标准"功能执行下一件事:
xmap :: (a -> b) -> f a -> g b
然后,我们不仅可以映射元素,还可以映射整个结构。
一些(不是真实的)例子
xmap id myBinaryTree :: [a]
目前,我必须进行明确的结构转换(典型的fromList
,toList
)然后
toList . fmap id -- if source struct has map
fmap id . fromList -- if destination struct has map
(要执行toStruct
,fromStruct
我使用fold
)。
是否存在某种推广to
/ from
结构的方法? (应该)
功能存在(xmap
)?
谢谢!! :)
答案 0 :(得分:5)
由于f
和g
是仿函数,因此您需要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
,我们知道f
是Foldable
。然后我们需要一些方法来构造g a
的元素并将它们组合在一起。我们可以使用Alternative
,我们需要它(pure
,empty
和<|>
),尽管我们也可以为此目的构造一些不太通用的类型类(我们在任何地方都不需要<*>
。
{-# 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]