Haskell-如何将map sum(map(x:)xss)转换为map(x+;)(map sum xss)

Haskell-如何将map sum(map(x:)xss)转换为map(x+;)(map sum xss),haskell,equational-reasoning,Haskell,Equational Reasoning,在阅读“Haskell的功能性思考”时,我遇到了一个程序计算的一部分,它要求将map sum(map(x:)xss)重写为map(x+)(map sum xss) 直觉上我知道这是有道理的 如果您有一些列表要求和,但是在求和之前,您还要向这些列表添加一个元素“x”,那么这与获取原始列表的和列表并向每个列表添加x的值是一样的 但我想知道如何仅使用等式推理将一个转换为另一个。我觉得我缺少了一条可以帮助我理解的法律或规则。我建议你看看类型,让它们引导你完成转换 > let xss = [[1],

在阅读“Haskell的功能性思考”时,我遇到了一个程序计算的一部分,它要求将
map sum(map(x:)xss)
重写为
map(x+)(map sum xss)

直觉上我知道这是有道理的

如果您有一些列表要求和,但是在求和之前,您还要向这些列表添加一个元素“x”,那么这与获取原始列表的和列表并向每个列表添加x的值是一样的


但我想知道如何仅使用等式推理将一个转换为另一个。我觉得我缺少了一条可以帮助我理解的法律或规则。

我建议你看看类型,让它们引导你完成转换

> let xss = [[1], [2], [3]]
> :t xss
xss :: Num t => [[t]]
> map sum xss     -- basically compacting the lists
[1,2,3]
> :t map sum xss  -- into just a list of numbers
map sum xss :: Num b => [b]
接下来我们需要做加法

> :t (+5)
(+5) :: Num a => a -> a
> :t map (+5)     --  no magic in this
map (+5) :: Num b => [b] -> [b]
> map (+5) (map sum xss)
[6,7,8]
我猜底线是,在第一个例子中,你改变类型的方式与在第二个例子中不同。列表列表变成列表的点会发生变化,因此添加数字的方式也会发生变化。

使用法则

map f (map g list) === map (f . g) list
我们可以推断

map sum (map (x:) xss) =
map (sum . (x:)) xss =
eta展开以提供一个要使用的参数

map (\xs -> sum . (x:) $ xs) xss =
用in代替
(f.g)x==f(gx)

在哪里

所以

替换
f(gx)==(f.g)x

降低λ

map ((x +) . sum) xss =
从上面看,使用第一定律的反面

map (x+) (map sum xss)

我不同意对清单的理解,但这当然是品味的问题。为什么不直接使用
(.)
的定义并说
map(sum.(x:))xss=map(\xs->sum(x:xs))xss=map(\xs->x+sum xs)=……
?@kosmikus Eh,个人品味。在这种情况下,它相当不重要,但我可以看到将
map
始终保持在那里的理由。@kosmikus看起来更好?有点:)但eta扩展是不必要的。lambda是通过减少
()
引入的。非常好。非常感谢。
map (\xs -> sum (x:xs)) xss =
map (\xs -> x + sum xs) xss =
map (\xs -> (x +) . sum $ xs) xss =
map ((x +) . sum) xss =
map (x+) (map sum xss)