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