问题描述
所以,这是一个类型定义,仅用于某些上下文:
type Name = String
type Coordinates = (Int,Int)
type Pop = Int
type TotalPop = [Pop]
type City = (Name,(Coordinates,TotalPop))
这是一个数据集:
testData :: [City]
testData = [("New York City",((1,1),[5,4,3,2])),("Washingotn DC",((3,3),[3,2,1,1])),("Los Angeles",((2,2),[7,7,5]))]
因此,我正在尝试创建一个函数 (addAllPops
) 来编辑 TotalPop
中所有 City
的 [City]
,并在开始时添加一个新条目TotalPop
。我希望它以这样的方式工作,在下面的示例中,输入 addNewPop testData [6,8]
会将它们更改为:
"New York City",[6,5,2],"Washingotn DC",[4,1],"Los Angeles",[8,5]
只改变一个城市人口的功能就在这里,连同我对整个城市的尝试,我最大的问题完全是将两个列表合并为一个。
addAllPops :: [City] -> [Int] -> [City]
addAllPops [(w,((x,y),z))] pops = [map uncurry addPop (zip pops z)]
addPop :: City -> Int -> City
addPop (w,z)) p = (w,p:z))
我已经被困在这个问题上很长时间了,非常感谢任何和所有的帮助:)
解决方法
您从 addPop
开始一次工作的直觉是正确的。现在看看 zipWith
的类型签名:
zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
它需要一个逐点操作的函数,并将其提升以并行操作两个列表。所以你 zipWith
城市和新元素列表,使用 addPop
逐点组合它们:
addAllPops :: [City] -> [Int] -> [City]
addAllPops cities newPops = zipWith addPop cities newPops
我们可以对这个定义进行 eta-contract 以得出惊人的简单
addAllPops = zipWith addPop
您也可以使用 zip
和 map
来完成此操作,但只是更麻烦。