I have created the following three types in Haskell:
type Product = (Int, String, Float)
type Order = (Product, Int)
type Purchase = [Order]
The idea is that every Product
has an ID (Int
), a name (String
) and a price (Float
). An Order
is a certain discrete quantity (Int
) of a given Product
. And a Purchase
is a list of Order
s.
With that, I have to create a function that takes two Purchase
s and then fuses them, returning another Purchase
in return. For example, if an input is [(product1, 2), (product1, 3), (product2, 4), (product2, 5), (product3, 10)]
, then the output should be [(product1, 5), (product2, 9), (product3, 10)]
. In other words, it removes all repeated Order
s, sums all quantities, and outputs the resultant "fused" Purchase
.
Here it is the function I currently have. It doesn't work, and Haskell points out several Couldn't match type
errors.
fusePurchases :: Purchase -> Purchase -> Purchase
fusePurchases p1 p2 = let productsIds = nub [productId | (aproduct, _) <- p1 ++ p2, let productId = fst aproduct] in [(aproduct, sum [snd p | p <- p1 ++ p2, fst (fst p) == productId])
| productId <- productsIds, let aproduct = head [prod | prod <- map fst (p1 ++ p2), fst prod == productId]]
What is wrong with it? What changes should be made? What would be an operating function?
Thanks!
I tried to create a single function and use list comprehension to merge the products into a list with unique elements in which the sum of all quantities of every Order
is summed according to the other Order
s with the same Product
.
The first error:
MergeOrders.hs:10:107-114: error:
• Couldn't match type: (Int, String, Float)
with: (a1, b1)
Expected: (a1, b1)
Actual: Product
• In the first argument of ‘fst’, namely ‘aproduct’
In the expression: fst aproduct
In an equation for ‘productId’: productId = fst aproduct
• Relevant bindings include
productId :: a1 (bound at MergeOrders.hs:10:91)
|
10 | fusionPurchases p1 p2 = let productsIds = nub [productId | (aproduct, _) <- p1 ++ p2, let productId = fst aproduct] in [(aproduct, sum [snd p | p <- p1 ++ p2, fst (fst p) == productId])
| ^^^^^^^^
arises because aProduct
has type Product
, which is a triple (Int, String, Float)
, but you have tried to apply the function fst
to it, and fst
is only applicable to pairs. In Haskell, applying fst
to a pair works:
> fst (1,2)
1
but applying it to a triple does not:
> fst (1,2,3)
<interactive>:1:5: error:
• Couldn't match expected type: (a, b0)
with actual type: (a0, b1, c0)
• In the first argument of ‘fst’, namely ‘(1, 2, 3)’
In the expression: fst (1, 2, 3)
In an equation for ‘it’: it = fst (1, 2, 3)
• Relevant bindings include it :: a (bound at <interactive>:1:1)
The other two errors result from similar problems. In each case, you are trying to apply fst
to a Product
triple.
You may find it helpful to define fst3
:
fst3 :: (a, b, c) -> a
fst3 (a, _, _) = a
With that definition, the following type checks okay:
fusionPurchases :: Purchase -> Purchase -> Purchase
fusionPurchases p1 p2
= let productsIds = nub [ productId | (aproduct, _) <- p1 ++ p2
, let productId = fst3 aproduct]
in [ (aproduct, sum [snd p | p <- p1 ++ p2, fst3 (fst p) == productId])
| productId <- productsIds
, let aproduct = head [ prod | prod <- map fst (p1 ++ p2)
, fst3 prod == productId]]