Mylies
Mylies

Reputation: 436

Haskell Unzip With Fold

I'm trying to figure out how to create a custom unzip function in Haskell using a custom version of fold (basically works as foldl) but I've become stuck. I can get it to

unzip' :: [(a,b)] -> ([a],[b])
unzip' = fold (\x->([x!!0],[x!!1])) ([],[])

But that errors out with:

• Couldn't match expected type ‘[a]’
              with actual type ‘(Integer, Integer)’
• In the first argument of ‘tail’, namely ‘(1, 2)’
  In the expression: tail (1, 2)
  In an equation for ‘it’: it = tail (1, 2)
• Relevant bindings include
    it :: [a] (bound at <interactive>:114:1)

From what I figure, x is (1,2) but I'm not sure how to further split it into 1 and 2. Here is the fold function that I am using:

fold :: (a -> b -> b) -> b -> ([a] -> b)
fold c n =
  let f [] = n
      f (x:xs) = x `c` (f xs)
  in f

Thank you

Upvotes: 1

Views: 1261

Answers (1)

TrebledJ
TrebledJ

Reputation: 8987

There are several issues with your lambda function.

Firstly, fold expects a (a -> b -> b), so technically, a function with two arguments. Right now, your lambda only accepts 1 argument. Since your fold resembles foldr (folds from the right), the second argument should be the accumulator object, which collects the result from each fold.

Secondly, you are working with tuples, not lists (as pdexter noted in a comment). Thus, you should use the fst and snd functions.

After some modifications to the lambda:

\x acc -> (fst x:fst acc, snd x:snd acc)

This will append the first element from each tuple to the first list of the accumulator. And the second element from each tuple to the second list of the accumulator. Some results:

unzip' :: [(a,b)] -> ([a],[b])
unzip' = fold (\x acc -> (fst x:fst acc, snd x:snd acc)) ([],[])

unzip' [(1, 'a'), (2, 'b'), (3, 'c')]
([1,2,3],"abc")

Following Jon's comment, you can also take advantage of pattern matching in the lambda, replacing fst and snd. This may increase the strictness of the function. You can also replace ([], []) with mempty, a predefined empty tuple.

unzip' = fold (\(x, y) (xs, ys) -> (x:xs, y:ys)) mempty

Tip: Before jumping into the unzip function, you could isolate and test out the lambda with your fold first.

Upvotes: 5

Related Questions