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

时间:2014-11-20 19:52:09

标签: haskell equational-reasoning

阅读“使用Haskell进行功能思考”我遇到了一个程序计算的一部分,需要将map sum (map (x:) xss)重写为map (x+) (map sum xss)

直觉我知道这很有道理......

如果你有一些你想要求和的列表,但是在求和之前,你还要添加一个元素'x',那么就像获取origninal列表的总和列表一样并为每个人添加x的值。

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

2 个答案:

答案 0 :(得分:12)

使用法律

map f (map g list) === map (f . g) list

我们可以推断出

map sum (map (x:) xss) =
map (sum . (x:)) xss =

eta-expand以提供与

一起使用的论据
map (\xs -> sum . (x:) $ xs) xss =

代入(f . g) x === f (g x)

map (\xs -> sum (x:xs)) xs =

其中

sum (x:xs) = x + sum xs
sum [] = 0

所以

map (\xs -> sum (x:xs)) xss =
map (\xs -> x + sum xs) xss =

代替f (g x) === (f . g) x

map (\xs -> (x +) . sum $ xs) xss =

eta-reduce the lambda

map ((x +) . sum) xss =

使用上面第一条法则的反向

map (x+) (map sum xss)

答案 1 :(得分:0)

我建议您查看类型并让它们指导您完成转换。

> 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]

我猜测的底线是,在第一个示例中,您以不同于第二个示例的方式更改类型。列表列表变为列表的位置发生变化,添加数字的方式也会发生变化。