为什么我不能使用迭代重复应用地图?

时间:2012-10-18 02:25:36

标签: haskell higher-order-functions lifting

我已经认识到,当我有嵌套数据结构时,我一直在手动编写代码来深入研究它们。像这样:

--one level
Prelude> map (*2) [1,2,3]
[2,4,6]

--nested two levels
Prelude> let t2 = map $ map (*2)
Prelude> t2 [[1,2,3],[4,5,6]]
[[2,4,6],[8,10,12]]

--nested three levels
Prelude> let t3 = map $ map $ map (*2)
Prelude> t3 [[ [1,2,3],[4,5,6] ],[ [1,2,3],[4,5,6] ]]
[[[2,4,6],[8,10,12]],[[2,4,6],[8,10,12]]]

所以我发现我应该能够自动构建一个函数,使用更高阶函数来深入研究我的嵌套数据结构:

Prelude> let t f n = (iterate map f) !! n

<interactive>:35:22:
    Occurs check: cannot construct the infinite type: b0 = [b0]
    Expected type: (a0 -> b0) -> a0 -> b0
      Actual type: (a0 -> b0) -> [a0] -> [b0]
    In the first argument of `iterate', namely `map'
    In the first argument of `(!!)', namely `(iterate map f)'

让我感到震惊

  1. 我理解它找到了一个预期的列表......别的什么
  2. 我不知道如何解决这个问题 - 我是否应该编写代码来重复应用程序,即使这就是我认为迭代的内容?
  3. 这似乎与“提升”的概念类似 - 但我不知道如何应用这种直觉。

2 个答案:

答案 0 :(得分:9)

问题是这些“迭代”有不同的类型。对于每次迭代,您都会获得额外的嵌套级别,因此您需要

t f 0 :: a -> b
t f 1 :: [a] -> [b]
t f 2 :: [[a]] -> [[b]]

但是iterate :: (a -> a) -> a -> [a]要求迭代都具有相同的类型。实际上,直接实现上述内容需要某种形式的依赖类型,因为返回类型取决于n的值。

除非你有充分的理由不这样做,否则我建议保持简单,只需写出所需数量的map来电。可以使用Template Haskell来生成它们,但这可能比它的价值更麻烦。

但是,如果您有复杂的嵌套数据结构,您可能需要查看SYB,它可以自动处理在嵌套结构中应用此类转换的样板。

这是一个简单的例子:

> import Data.Generics
> let t x = everywhere (mkT (*2)) x
> :t t
t :: Data a => a -> a
> t [2,4,6]
[4,8,12]
> t [[2,4,6],[8,10,12]]
[[4,8,12],[16,20,24]]
> t (Just [(1, 2, 3), (4, 5, 6)])
Just [(2,4,6),(8,10,12)]

答案 1 :(得分:3)

考虑(iterate map f) !! n的类型。您希望a -> an = 0[a] -> [a]n = 1[[a]] -> [[a]]n = 2 - 通常,您需要此类型表达式取决于n。但是在Haskell中这是不可能的,因为它不是一种依赖类型的语言。