将函数应用于项列表

时间:2014-04-22 12:52:32

标签: haskell functional-programming

我定义了一个函数f,它返回项price的{​​{1}},该项x存储在类型为[(String,String,Int)]的价格列表中

a = String
x = String
price = Int
pricesList = [(a,x,price)]

f a x ((a1, x1, price):ys) | a == a1 && x == x1 = price
                           | otherwise = f a x ys

我必须将此功能应用于项目列表,但我被卡住了。这可能使用地图吗?我无法理解。

(唯一可以使用递归的函数是f)

修改。一些例子来澄清一点

pricesList = [("apple","ipod",100),("apple","iphone",200),("samsung","galaxy",200)]
moneySpent = [("harry",1985,"apple",["iphone","ipod"]),("george",1983,"samsung",["galaxy"])]

*Main> f "apple" "iphone" pricesList
200

我需要知道一个人通过定义新功能花了多少钱,让我们说spentBy(并在其中使用f

*Main> spentBy "harry"
300

到目前为止我做了什么:

itsThePerson name (n,_,_,_) = name == n

infoFrom name = (head . filter (itsThePerson name)) moneySpent

brand (_,_,b,_) = b
product (_,_,_,p) = p

brandPerson = brand . infoFrom
productPerson = product . infoFrom

是否可以使用功能map的{​​{1}}来了解某人购买的产品的价格总和?

(函数f将是函数f

itemPrice

我是否正在朝着正确的方向思考?

4 个答案:

答案 0 :(得分:3)

假设你有三个参数函数:

f :: a -> b -> c -> d

以及c值列表 - list :: [b]。假设我们希望将f应用于列表中的每个项目,并使用固定的第一个和第二个参数。所以我们可以这样做:

map (f x y) list

其中x::ay::b

与你的案例的唯一区别是参数的顺序。对于此类问题,请使用flip

flip :: (a -> b -> c) -> (b -> a -> c)

--original function
f :: a -> b -> c -> d

--partial application
f x :: b -> c -> d

-- flip
flip (f x) :: c -> b -> d

--partial application again
(flip (f x) y) :: b -> d

map (flip (f x) y) list :: [d]

在你的情况下,它可能会导致类似map (flip (f a) prices) list

答案 1 :(得分:2)

如果您为f提供了类型签名,那么您尝试执行的操作会更清楚。我将假设f的第三个参数是(item #, description, price)的列表。一个例子是:

priceList = [(1,"item 1", 1), (2,"item 2", 22), (3, "item 3", 333), (4, "item 4", 4444)]

然后我们计划映射的列表必须如下所示:

list = [(1,"item 1"), (3,"item 3"), (4, "item 4")]

我们可以这样映射list

map (\(itemId, desc) -> f itemId desc priceList) list

您可以改为编写f来获取两个参数,将前两个参数组合成一个元组f (a,x) ((a1, x1, price):ys)。您所需要的只是map f list

最后,您还没有处理价格不在列表中的情况。你可以这样做:

 f _ _ _ = error "item not found"

答案 2 :(得分:1)

修改后的答案: 你要解决的整体问题,

  • 给定一个带'itemId','itemName'和'priceList'的函数f 并返回一个价格。
  • 您想要一个使用f从[(itemId,itemName)]列表中返回价格列表的函数

在类型签名方面,给出:

f :: String -> String -> [(String, String, Int)] -> Int

你想要:

myLookup :: (String -> String -> [(String, String, Int)] -> Int) -> 
                [(String, String, Int)] -> [(String, String)] -> [Int]

其中第一个参数是查找函数f,priceList和itemList,输出是价格列表。

myLookup f priceList itemList = map (\(itemId, itemName) -> 
                                          f itemId itemName priceList)
                                    itemList

map的第二个参数是一个lambda,它从itemList中提取两个属性,并使用f查找值。

答案 3 :(得分:0)

我可以解决我的问题:

f a x ((a1, x1, price):ys) | a == a1 && x == x1 = price
                           | otherwise = f a x ys

使用了新功能f2

f2 a x = f a x pricesList

然后

pricesList = [("apple","ipod",100),("apple","iphone",200),("samsung","galaxy",200)]
moneySpent = [("harry",1985,"apple",["iphone","ipod"]),("george",1983,"samsung",["galaxy"])]


spentBy name = sum (map (f2 (brandPerson name)) (productPerson name))

itsThePerson name (n,_,_,_) = name == n

infoFrom name = (head . filter (itsThePerson name)) moneySpent

brand (_,_,b,_) = b
product (_,_,_,p) = p

brandPerson = brand . infoFrom
productPerson = product . infoFrom