2

i am trying to write a very simple function in haskell to change a value in a list depending on an input as follows

update_game :: [Int] -> Int -> Int -> [Int]
update_game (x:xs) row take_amnt | row == 1 = x - take_amnt:xs
                                 | row == 2 = x : head(xs) - take_amnt : tail(xs)
                                 | row == 3 = x : head(xs) : last(xs) - take_amnt`

the first two cases work fine, however the last case is causing me problems and im not sure why, the errors i get are :

https://i.stack.imgur.com/jpT8b.png

https://i.stack.imgur.com/tlz5t.png

dreamcrash
  • 47,137
  • 25
  • 94
  • 117
Amman Vedi
  • 21
  • 1
  • 4
    In the Windows console, you can copy text by clicking the window icon, selecting “Mark”, making your selection, and hitting Enter to copy it to the clipboard. – Jon Purdy Dec 17 '12 at 21:43

3 Answers3

2

The second argument to : should be a list, but last(xs) - take_amnt apparently yields only a single element. Try

row == 3 = x : head(xs) : [last(xs) - take_amnt]
Frerich Raabe
  • 90,689
  • 19
  • 115
  • 207
2
last(xs) - take_amnt

is an Int, but the second argument of (:) must be a list, since (:) :: a -> [a] -> [a].

If your lists are always three elements long (but then you should probably use a tuple instead of a list), as it seems, wrapping that in a [ ] would solve it with the correct semantics,

update_game :: [Int] -> Int -> Int -> [Int]
update_game (x:xs) row take_amnt | row == 1 = x - take_amnt:xs
                                 | row == 2 = x : head(xs) - take_amnt : tail(xs)
                                 | row == 3 = x : head(xs) : [last(xs) - take_amnt]

However, it would be better to pattern-match accordingly

update_game [x,y,z] 1 take_amnt = [x - take_amnt, y, z]
update_game [x,y,z] 2 take_amnt = [x, y - take_amnt, z]
update_game [x,y,z] 3 take_amnt = [x, y, z - take_amnt]
update_game _       _ _         = error "Invalid input"

or make it generic without pattern matching

update_game xs index take_amnt = zipWith (-) xs (replicate (index-1) 0 ++ take_amnt : repeat 0)
Daniel Fischer
  • 181,706
  • 17
  • 308
  • 431
  • Your alternative `update_game` definition would yield an error whereas the original function would yield `[1]` for `update_game [1] 1 0`. – Frerich Raabe Dec 17 '12 at 20:38
  • Well, it's based on the explicitly mentioned assumption that the lists always have exactly three elements. – Daniel Fischer Dec 17 '12 at 20:41
  • @FrerichRaabe if i'm not mistaken, in the original code this would cause `head []` to be called, which would cause an error. – Will Ness Dec 17 '12 at 20:46
  • @WillNess: In `update_game [1] 1 0`, `row == 1` holds, hence `x - take_amnt:xs` is used; no `head` call there. – Frerich Raabe Dec 17 '12 at 21:39
2

The second parameter in ":" should be a list, last(xs) - take_amnt gives an element only.

wrap it in "[]" which would be [last(xs) - take_amnt]

Viktor Mellgren
  • 4,318
  • 3
  • 42
  • 75