Haskell 是否可以使用map定义foldr?
在我使用Haskell 是否可以使用map定义foldr?,haskell,fold,higher-order-functions,map-function,Haskell,Fold,Higher Order Functions,Map Function,在我使用foldr定义了map之后,我想到了一个问题: 如果可以使用foldr定义map,那么相反的情况如何 在我看来这是不可能的,但我找不到一个恰当的解释。 谢谢你的帮助 如果你做了某种作弊助手函数: f [x] a = x a f (x:xs) a = f xs (x a) foldr g i xs = f (map g $ reverse xs) i sum :: [Int] -> Int 让我们从一些类型签名开始 foldr :: (a -> b -> b) -&
foldr
定义了map
之后,我想到了一个问题:
如果可以使用foldr
定义map
,那么相反的情况如何
在我看来这是不可能的,但我找不到一个恰当的解释。
谢谢你的帮助 如果你做了某种作弊助手函数:
f [x] a = x a
f (x:xs) a = f xs (x a)
foldr g i xs = f (map g $ reverse xs) i
sum :: [Int] -> Int
让我们从一些类型签名开始
foldr :: (a -> b -> b) -> b -> [a] -> b
map :: (a -> b) -> [a] -> [b]
我们可以使用fold
来模拟map
,因为fold
是一个通用的操作符(“这是一篇关于这个属性的更数学但非常友好的论文”)
我确信有一些创造性的方法可以使用map
来模拟foldr
。这当然是一个有趣的练习。但我不认为有一个直接的、非“疯狂无点”的解决方案,为了解释它,让我们暂时忘记foldr
,集中讨论一个更简单的累积函数:
f [x] a = x a
f (x:xs) a = f xs (x a)
foldr g i xs = f (map g $ reverse xs) i
sum :: [Int] -> Int
sum==foldr(+)0
,这意味着foldr
实现了sum
。如果我们能用map
实现foldr
,我们肯定能用map
实现sum
。我们能做到吗
我认为sum
的签名是一个巨大的打击-sum
返回一个Int
,而map
总是返回一个列表。因此,也许map
可以完成繁重的工作,但我们仍然需要另一个[a]->a
类型的函数才能得到最终结果。在本例中,我们需要类型为[Int]->Int
的函数。这是非常不幸的,因为这正是我们一开始想要避免的
因此,我想答案是:你可以使用
map
实现foldr
——但它可能需要使用foldr
:)查看它的最简单方法是看到map
保留了列表的脊梁。如果你看一看更一般的fmap(这是一种映射,但不只是针对列表,而是针对Functor
s),它甚至是一条规律
fmap id = id
“作弊”的方法有很多,但从最直接的角度来看,褶皱比地图更为普遍。Edward Kmett的镜头库中经常使用一个很好的技巧。考虑<代码> const <代码>单元格,定义如下:
newtype Const a b = Const { runConst :: a }
instance Functor (Const a) where fmap _ (Const a) = Const a
instance (Monoid a) => Monad (Const a) where
return _ = Const mempty
Const a >>= Const b = Const (a <> b)
map
输出与它得到的长度相同的列表foldr
可以输出任意长度的列表,或者根本不是列表的内容。有些相关:您必须更具体一点。请注意,可以定义foldr
而不使用模式匹配,因此您当然可以使用模式匹配和map
来定义它。当然,这仍然只是一个折页。它只是通过幺半群分配了组合器和零元素。Const a>=Const b=Const(a b)
没有进行打字检查。读到这篇文章时,我不禁想到“Curry Howard又罢工了”;-)如果允许使用zip
,并且添加了last
-也可以使用foldl
,尤其是sum
。无限列表上的延迟foldr
可能是问题。此f
是f=foldl(>>>)id=foldr(.)id。反向
所以它甚至没有作弊,它只是再次折叠,foldr(.)id(反向$map g$反向xs)i=foldr((.).g)id xs i=foldr g i xs
。