Reputation: 49
I have defined a function f
that returns the price
of an item x
that is stored inside a list of prices with type [(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
I have to apply this function to a list of items, but I'm stuck. Is this possible using map? I couldn't figure it out.
(The only function that can use recursion is f)
Edit. some examples to clarify a bit
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
I need to know how much money a person spent by defining a new function, let's say spentBy
(and using f
inside of it)
*Main> spentBy "harry"
300
What I have done so far:
itsThePerson name (n,_,_,_) = name == n
infoFrom name = (head . filter (itsThePerson name)) moneySpent
brand (_,_,b,_) = b
product (_,_,_,p) = p
brandPerson = brand . infoFrom
productPerson = product . infoFrom
Is it possible to use map
with function f
to know the sum of the prices of the products that a person bought?
(function f
would be function itemPrice
)
spentBy name = sum (map (itemPrice (brandPerson name) xxx pricesList) (productPerson name)
Am I thinking it in the right direction?
Upvotes: 0
Views: 214
Reputation: 49
I could solve my problem:
f a x ((a1, x1, price):ys) | a == a1 && x == x1 = price
| otherwise = f a x ys
Used a new function f2
f2 a x = f a x pricesList
Then
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
Upvotes: 0
Reputation: 4166
Modified answer: The overall problem you're trying to solve,
In terms of type signatures, given:
f :: String -> String -> [(String, String, Int)] -> Int
and you want:
myLookup :: (String -> String -> [(String, String, Int)] -> Int) ->
[(String, String, Int)] -> [(String, String)] -> [Int]
where the first argument is the lookup function f
, a priceList and an itemList, and the output is a list of prices.
myLookup f priceList itemList = map (\(itemId, itemName) ->
f itemId itemName priceList)
itemList
The second argument to map
is a lambda that extracts the two attributes from the itemList and looks up the values using f
.
Upvotes: 1
Reputation: 8136
If you provided a type signature for f
, it would be clearer what you were trying to do. I'm going to assume that the third argument of f
is a list of (item #, description, price)
. An example would be:
priceList = [(1,"item 1", 1), (2,"item 2", 22), (3, "item 3", 333), (4, "item 4", 4444)]
Then the list we plan to map over must look something like this:
list = [(1,"item 1"), (3,"item 3"), (4, "item 4")]
We can map over list
like so:
map (\(itemId, desc) -> f itemId desc priceList) list
You could instead write f
to take two parameters, combining the first two into a tuple f (a,x) ((a1, x1, price):ys)
. The all you need is map f list
.
Finally, you haven't handled the case where the price isn't in the list. You could do something like this:
f _ _ _ = error "item not found"
Upvotes: 2
Reputation: 3428
Let's say you've got a three-argument function:
f :: a -> b -> c -> d
and a list of c
values - list :: [b]
. Let's say we want to apply f
to each item in the list, with fixed first and second arguments. So we can do something like that:
map (f x y) list
where x::a
and y::b
.
The only difference from your case is the order of arguments. For this kind of issues, use 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]
In your case it'll probably result in something like map (flip (f a) prices) list
.
Upvotes: 3