# Could not match the expected type `(t1, t2, t0) 'with the actual type` [a0]`

advertisements

I'm trying to solve a fractional knapsack problem with the input,

``````[("label 1", value, weight), ("label 2", value, weight), ...]
```
```

and the output,

``````[("label 1", value, solution_weight), ("label 2", value, solution_weight), ...]
```
```

but I keep getting the error in `computeKnapsack`:

``````"Couldn't match expected type `(t1, t2, t0)' with actual type `[a0]`"
```
```

I can't understand what the problem might be. I'm trying to create a list of 3-entry tuples. How can I get it to stop expecting a single 3-entry tuple?

``````fst3 (a,b,c) = a
snd3 (a,b,c) = b
trd3 (a,b,c) = c
fst4 (a,b,c,d) = a
snd4 (a,b,c,d) = b
trd4 (a,b,c,d) = c
qud4 (a,b,c,d) = d

sortFrac (a1, b1, c1, d1) (a2, b2, c2, d2)
| d1 > d2 = GT
| d1 <= d2 = LT

fracKnap (x:xs) =
fractionalKnapsack (x:xs) []

fractionalKnapsack (x:xs) fracList =
if length (x:xs) <= 1
then computeKnapsack (sortBy sortFrac (((fst3 x),(snd3 x),(trd3 x),(snd3 x) / (trd3 x)):fracList)) 100
else fractionalKnapsack xs (((fst3 x),(snd3 x),(trd3 x),(snd3 x) / (trd3 x)):fracList)

computeKnapsack (x:xs) weightLeft =
if length (x:xs) <= 1
then (fst4 x, snd4 x, ((floor (weightLeft / (qud4 x)))*(qud4 x)))
else (fst4 x, snd4 x, ((floor (weightLeft / (qud4 x)))*(qud4 x))):(computeKnapsack xs (weightLeft-(floor (weightLeft / (qud4 x))*(qud4 x))))
```
```

In the `then` branch of `computeKnapsack` the result is a single 3-tuple, but in the `else` branch it is a list of 3-tuples.

I'm going to rewrite `computeKnapsack` for you. I'll start with your version with the error fixed:

``````computeKnapsack (x:xs) weightLeft =
if length (x:xs) <= 1
then [(fst4 x, snd4 x, ((floor (weightLeft / (qud4 x)))*(qud4 x)))]
else  (fst4 x, snd4 x, ((floor (weightLeft / (qud4 x)))*(qud4 x))) : (computeKnapsack xs (weightLeft-(floor (weightLeft / (qud4 x))*(qud4 x))))
```
```

First, I'm going to say what happens if the first argument to `computeKnapsack` is the empty list:

``````computeKnapsack []     _          = []
computeKnapsack (x:xs) weightLeft =
(fst4 x, snd4 x, ((floor (weightLeft / (qud4 x)))*(qud4 x))) : (computeKnapsack xs (weightLeft-(floor (weightLeft / (qud4 x))*(qud4 x))))
```
```

It enables us to get rid of the `if`-test, making the code shorter overall and easier to understand.

Next, I'll deconstruct `x`:

``````computeKnapsack []             _          = []
computeKnapsack ((a,b,_,d):xs) weightLeft =
(a, b, ((floor (weightLeft / d))*d)) : (computeKnapsack xs (weightLeft-(floor (weightLeft / d)*d)))
```
```

You might prefer to follow leftaroundabout's suggestion to create a record type with meaningful names instead. But if you do continue to use a tuple, deconstructing it by pattern matching is much clearer than using your `fst4`, `snd4` etc functions.

Again, the code is now shorter and easier to understand, though it might help if we used more meaningful names than `a`, `b`, and `d`.

We can continue in this vein:

``````computeKnapsack []             _          = []
computeKnapsack ((a,b,_,d):xs) weightLeft = (a, b, weight) : (computeKnapsack xs (weightLeft - weight))
where weight = floor (weightLeft / d) * d
```
```

Here I've spotted that the same value was being calculated in two different places, and extracted that value into its own named variable. `weight` only needs to be calculated once instead of twice, so `computeKnapsack` is now marginally more efficient. More importantly, I now understand what `computeKnapsack` is doing.

I understand that you're new to Haskell. Please take this as constructive suggestions on how you can write clearer Haskell code.