1

I have some code like this:

data Set = Set String [Int]
  deriving (Show, Read)
getArr :: Set -> [Int]
getArr (Set _ arr) = arr

My goal is to write a function that will input a list of values into a tuple. EG: data -- "One" [1], "Two" [2], "Three" [3] output: "One" [0, 1], "Two" [1,2], "Three" [3,3] with the input being [0, 1, 3]

My general aproach to this was to go recursively over the data going one by one and at the same time going over the list of values one by one using : to add it onto the first index.

I attempted to do something like:

addToSet :: [Set] -> [Int] -> [Set]
addToSet [] [] = []
addToSet (x:xs) (y:ys) = (getArr x : y) ++ addToSet xs

but i get an error saying :

Couldn't match type ‘[Int]’ with ‘Set’
  Expected type: [Set]
    Actual type: [[Int]]```

1
  • 1
    there is a lot going on here - first get Arr x : y would result in a Int-list (result of getArr) being prepended to a [Int]` (the y) - then the result of that (what ever it is supposed to be) is concatenated with a [Int] -> [Set] (you only partial applied xs to addToSet) ... also: can you please make a better example (input to addToSet and expected output)? Your example on the first half does not seem to associated to the second half at all Commented Apr 29, 2021 at 17:03

1 Answer 1

1

Consider the helper function

updateSet :: Set -> Int -> Set
updateSet (Set s xs) y = Set s (y:xs)

This simply adds a single value to a given set:

>>> updateSet (Set "One" [1]) 0
Set "One" [0,1]

Then addToSet is just a wrapper around zipWith:

addToSet :: [Set] -> [Int] -> [Set]
addToSet = zipWith updateSet

updateSet is called on the first set and the first integer, then the second set and the second integer, and so on, with the results combined in order in a single list.


Another way to think of this is mapping a function of type (Set, Int) -> Int over the result of zipping the two lists together:

updateSet' :: (Set, Int) -> Set
updateSet' (Set s xs, y) -> Set s (y:xs)

addToSet :: [Set] -> [Int] -> [Set]
addToSet ss is = map updateSet' (zip ss is)

Note that updateSet' = uncurry updateSet.

Sign up to request clarification or add additional context in comments.

6 Comments

I understand your explanation and appreciate it but I tried running addToSet(sampleSet [0, 1, 3]) but im getting an error
The parentheses are used wrong. The call is simply addToSet sampleSet [0, 1, 3].
Specifically, parentheses aren't used in function calls, unless to define a subexpression as a single argument. The function call itself is just the function and its argument separated by a space. Note that foo x y is two function calls: foo x returns a function which is then applied to y. Informally, you can think of that as a single call to foo taking two arguments.
I sometimes wonder whether we do new Haskellers a disservice with the "function application is juxtaposition" line. Maybe it would be kinder to teach them "all functions take one argument" and "use parens for application" just like other languages. So foo(x)(y)(z) because we apply foo to x, then apply foo(x) to y, then apply foo(x)(y) to z. Then at some later date, we can tell them that as a notational convenience you're allowed to drop parens around single tokens or something. ...but I'm sure there'd be some new confusion then that the current way doesn't have. Sigh.
Haskell just uses higher level abstractions. map and zip basically "hide" the recursion from you, by representing very commonly used patterns. It's similar to how you can write a + b, rather than iterating over the bits of a and b yourself and using AND and XOR to implement the half-adders.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.