【问题标题】:Is it possible to define foldr using map?是否可以使用地图定义文件夹?
【发布时间】:2014-05-24 22:22:32
【问题描述】:

在我使用foldr 定义map 之后,我想到了一个问题:

如果可以使用foldr 定义map,那么相反呢?

在我看来这是不可能的,但我找不到合适的解释。 感谢您的帮助!

【问题讨论】:

  • map 输出一个长度相同的列表。 foldr 可以输出任意长度的列表,或者根本不是列表的东西。
  • 你必须更具体一点。请注意,可以定义 foldr 而不使用除模式匹配之外的任何其他内容,因此您当然可以使用模式匹配 map 来定义它。

标签: haskell fold higher-order-functions map-function


【解决方案1】:

让我们从一些类型签名开始。

foldr :: (a -> b -> b) -> b -> [a] -> b
map :: (a -> b) -> [a] -> [b]

我们可以使用fold 模拟map,因为fold 是一个通用运算符(here 是关于此属性的更数学但非常友好的论文)。

我确信有一些创造性的方法可以使用map 来模拟foldr。这当然可以是一个有趣的练习。但我不认为有一个直接的,而不是“疯狂的无点”解决方案,为了解释它,让我们暂时忘掉foldr,专注于一个更简单的累积函数:

sum :: [Int] -> Int

sum == foldr (+) 0,表示foldr实现sum。如果我们可以用map 实现foldr,我们肯定可以用map 实现sum。我们能做到吗?

我认为sum 的签名是一个致命的打击——sum 返回一个Int,而map 总是返回一个列表。所以也许map 可以完成繁重的工作,但我们仍然需要[a] -> a 类型的另一个函数才能获得最终结果。在我们的例子中,我们需要一个[Int] -> Int 类型的函数。这很不幸,因为这正是我们一开始就试图避免的。

所以我猜答案是:你可以使用map 来实现foldr - 但它可能需要使用foldr :)

【讨论】:

  • 读到这里时,我忍不住想“库里-霍华德又来了”;-)
  • 如果zip 被允许,scanl can be implemented with map,加上last - 还有foldl,特别是sum。无限列表上的懒惰foldr 可能是个问题。
【解决方案2】:

查看它的最简单方法是查看map 保留了列表的主干。如果您查看更通用的 fmap(它是 map,但不仅适用于列表,而且一般适用于 Functors),它甚至是一个法律

fmap id = id

有很多方法可以“作弊”,但在对您的问题最直接的解释中,折叠比地图更普遍。 Edward Kmett 的镜头库中有一个很好的技巧。考虑Const monad,其定义如下:

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)

现在您可以根据单子映射操作mapM 制定折叠,只要结果类型是单曲面:

fold :: Monoid m => [m] -> m
fold = runConst . mapM Const

【讨论】:

  • 当然,这仍然只是一个折叠。它只是将组合器和零元素分布在幺半群中。
  • Const a &gt;&gt;= Const b = Const (a &lt;&gt; b) 不进行类型检查。
【解决方案3】:

如果你做了某种作弊辅助功能:

f [x] a = x a
f (x:xs) a = f xs (x a)

foldr g i xs = f (map g $ reverse xs) i

【讨论】:

  • 这个ff = foldl (&gt;&gt;&gt;) id = foldr (.) id . reverse 所以它甚至不是作弊,它只是再次折叠,foldr (.) id (reverse $ map g $ reverse xs) i = foldr ((.).g) id xs i = foldr g i xs
猜你喜欢
  • 2012-04-29
  • 1970-01-01
  • 2021-04-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-12
  • 2021-07-14
相关资源
最近更新 更多