Unpair list of tuples - list

I have this excercise in Haskell where we have a list of tuples and we need to unpair them and put them into different lists.
Desired outcome:
Main> unpair [(1,2),(3,4),(5,6)]
([1,3,5],[2,4,6])
My code, but I get some errors:
unpair :: [(a,b)] -> ([a],[b])
unpair list = ([a|a<-list.fst], [b|b<-list.snd])
errors:
Template.hs:8:22:
Couldn't match expected type `b0 -> c0' with actual type `[(a, b)]'
Relevant bindings include
list :: [(a, b)] (bound at Template.hs:8:8)
unpair :: [(a, b)] -> ([a], [b]) (bound at Template.hs:8:1)
In the first argument of `(.)', namely `list'
In the expression: list . fst
Template.hs:8:22:
Couldn't match expected type `[a]'
with actual type `(b0, b1) -> c0'
Relevant bindings include
list :: [(a, b)] (bound at Template.hs:8:8)
unpair :: [(a, b)] -> ([a], [b]) (bound at Template.hs:8:1)
In the expression: list . fst
In a stmt of a list comprehension: a <- list . fst
In the expression: [a | a <- list . fst]
Template.hs:8:39:
Couldn't match expected type `b2 -> c1' with actual type `[(a, b)]'
Relevant bindings include
list :: [(a, b)] (bound at Template.hs:8:8)
unpair :: [(a, b)] -> ([a], [b]) (bound at Template.hs:8:1)
In the first argument of `(.)', namely `list'
In the expression: list . snd
Template.hs:8:39:
Couldn't match expected type `[b]'
with actual type `(a0, b2) -> c1'
Relevant bindings include
list :: [(a, b)] (bound at Template.hs:8:8)
unpair :: [(a, b)] -> ([a], [b]) (bound at Template.hs:8:1)
In the expression: list . snd
In a stmt of a list comprehension: b <- list . snd
In the expression: [b | b <- list . snd]
The question also states to try to do it with list comprehensions.
Thanks

This is only slightly hinted to by your error message. The problem you have is that you are mis-using the . operator. You might have programmed in an object-oriented language before where list.fst calls a function fst on the list object. This is not the case in Haskell where . is an infix function used to compose two functions.
What you really want to do is to pick tuples from your list, and then apply fst/snd on those tuples one at a time. For example:
[fst a | a <- list]
You can also use pattern matching and skip fst/snd altogheter, but it is a matter of opinion if this is better or worse:
[a | (a, _) <- list]

You're almost right! You've just got some minor errors:
In Haskell, you can't do list.fst - that is syntactically valid, but the . operator doesn't do the same thing in Haskell as it does in other languages. fst is a function and should be used as such - try applying it to a value e.g. fst list.
More significantly, you can't apply fst or snd to a list like list; as Haskell is a strongly typed language, these functions must be applied to a single value, not a list. Try moving these functions to the left of the bar e.g. to get all the fst values in a list, use [fst a | a <- list], meaning 'for each value a in list, apply fst to a'.

Related

Apppend a list in a list of list - Haskell

I'm trying to do a function in haskell. The purpose of the function is to add a list to an existing list of list.
[Int] -> [[Int]] -> [[Int]]
I wish it would work like :
[1] -> [[2],[3]] -> [[2],[3],[1]]
I would like to know how I can proceed to do that. There is an existing included function to do that?
You can wrap the element [1] in a singleton list, and then append the two lists with (++) :: [a] -> [a] -> [a]. So you can implement such function with:
addlast :: a -> [a] -> [a]
addlast x ys = ys ++ [x]
The (++) function however will usually take linear time in the number of elements of the left operand (so ys), which makes it computationally expensive. Therefore it is usually better if order does not matter to prepend to a list.
In the extra package [Hackage], you can make use of snoc :: [a] -> a -> [a]. In that case, this is thus a "flipped" version of snoc:
import Data.List.Extra(snoc)
addlast :: a -> [a] -> [a]
addlast = flip snoc

Concatenation in Haskell and confusion with AList ([a] -> [a])

I have a project where we are improving the speed of concatenating a list in Haskell.
I'm new to Haskell and confused about AList ([a] -> [a]) Specifically how to convert my AppendedList to a regular List. Any help would be appreciated.
newtype AppendedList a = AList ([a] -> [a])
-- List[5] is represented as AList (\x -> 5:x)
-- This function takes an argument and returns the AppendedList for that
single :: a -> AppendedList a
single m = AList (\x -> m : x)
-- converts AppendedList to regular List
toList :: AppendedList a -> [a]
toList = ???
The toughest part is to not give you the answer directly :)
If you remember how lists are constructed in Haskell: [1, 2, 3] = 1 : 2 : 3 : [], with [] being the empty list.
Now let's "follow the types" (we also call this thought process TDD for Type Driven Development) and see what you have at hand:
toList :: AppendedList a -> [a]
toList (AList listFunction) = ???
and listFunction has the type [a] -> [a]. So you need to provide it a polymorphic list (i.e. a list of any type) so that it gives you back a list.
What is the only list of any type you know of? Pass this list to listFunction and everything will compile, which is a good indicator that it's probably right :D
I hope that helps without providing the plain answer (the goal is for you to learn!).
AppendedList a is a type.
AList f is a datum of that type, with some function f :: [a] -> [a] "inside it".
f is a function from lists to lists with the same type of elements.
We can call it with some_list :: [a] to get resulting_list :: [a]:
f :: [a] -> [a]
some_list :: [a]
-------------------------
f some_list :: [a]
resulting_list :: [a]
resulting_list = f some_list
We can use resulting_list as some_list, too, i.e..
resulting_list = f resulting_list
because it has the same type, that fits f's expectations (and because of Haskell's laziness). Thus
toList (...) = let { ... = ... }
in ...
is one possible definition. With it,
take 2 (toList (single 5))
would return [5,5].
edit: Certainly [5,5] is not the list containing a single 5. Moreover, take 4 ... would return [5,5,5,5], so our representation contains any amount of fives, not just one of them. But, it contains only one distinct number, 5.
This is reminiscent of two Applicative Functor instances for lists, the [] and the ZipList. pure 5 :: [] Int indeed contains just one five, but pure 5 :: ZipList Int contains any amount of fives, but only fives. Of course it's hard to append infinite lists, so it's mainly just a curiosity here. A food for thought.
In any case it shows that there's more than just one way to write a code that typechecks here. There's more than just one list at our disposal here. The simplest one is indeed [], but the other one is .... our list itself!

A Haskell List Involving Recursion and High Order Functions

Now I have this code that takes a list and does something to the first element and then to every other one. And it returns a list of the transformed elements. The problem I am having is that I want to have a list that contains the untransformed and the transformed elements. This is what I have so far:
applyToEveryOther :: (a -> b) -> [a] -> [b]
applyToEveryOther _ [] = []
applyToEveryOther f [x] = [f x]
applyToEveryOther f (x:y:xs) = f x : y : applyToEveryOther f xs
The error it is giving me says there is a problem with the : y part of the function
When I try your code, I get the following (admittedly somewhat lengthy and confusing) error message:
EveryOther.hs:4:42: error:
• Couldn't match type ‘b’ with ‘a’
‘b’ is a rigid type variable bound by
the type signature for:
applyToEveryOther :: forall a b. (a -> b) -> [a] -> [b]
at EveryOther.hs:1:22
‘a’ is a rigid type variable bound by
the type signature for:
applyToEveryOther :: forall a b. (a -> b) -> [a] -> [b]
at EveryOther.hs:1:22
Expected type: [a]
Actual type: [b]
• In the second argument of ‘(:)’, namely ‘applyToEveryOther f xs’
In the second argument of ‘(:)’, namely
‘y : applyToEveryOther f xs’
In the expression: f x : y : applyToEveryOther f xs
• Relevant bindings include
xs :: [a] (bound at EveryOther.hs:4:26)
y :: a (bound at EveryOther.hs:4:24)
x :: a (bound at EveryOther.hs:4:22)
f :: a -> b (bound at EveryOther.hs:4:19)
applyToEveryOther :: (a -> b) -> [a] -> [b]
(bound at EveryOther.hs:2:1)
However, it's worth trying to figure out what GHC is saying here. As per the second bullet point, GHC was processing the subexpression y : applyToEveryOther f xs, and specifically looking at the second argument to the : operator in that expression (namely applyToEveryOther f xs. It expected that expression to have type [a], but the actual type of the expression was type [b].
Here, a and b are both "rigid" types, meaning simply that they were specified explicitly by the programmer. GHC also notes, in the relevant bindings, that y had type a.
So, to sum up, you asked GHC to evaluate the expression:
y : applyToEveryOther f xs
where you already specified that y had type a and applyToEveryOther f xs had type [b], and GHC refused to do this because lists in Haskell can't mix two different types.
And that's kind of the key to the whole problem. You want to transform some of the elements of your [a] list from a to b, but then you want to return a mixed list of as and bs. Haskell can't do that!
The only way your function can work is if you change the signature so that a and b are the same type:
applyToEveryOther :: (a -> a) -> [a] -> [a]
and your code will work fine.
Another way you could "discover" the correct signature is to leave it out and have Haskell infer the most general possible signature. If you load the code (without the explicit signature) into GHCi and ask for the type, you get:
> :t applyToEveryOther
applyToEveryOther :: (a -> a) -> [a] -> [a]
>
which is the most general possible type for this function.
If I understood correctly you wanted both, the original and transformed values.
However evaluating applyToEveryOther (+3) [0,1,2] returns [3,1,5]. If you want [0,3,1,4,2,5] as a result, try
applyToEveryOther _ [] = []
applyToEveryOther f [x] = [x,f x]
applyToEveryOther f (x:xs) = x: f x : applyToEveryOther f xs

Swapping tuples in a list of tuples

I tried to write a code which is capable of swapping tuples in a list of tuples like that:
[("a","b"),("c","d")] --> [("b","a"),("d","c")]
tupleXTurn :: [(String,String)]->[(String,String)]
tupleXTurn (x:xs) = (snd x,fst x) ++ (tupleXTurn xs)
There's an error corresponding the types.
Thanks alot!
The Error is:
Couldn't match type ‘xs’ with ‘String’
‘xs’ is a rigid type variable bound by
an expression type signature: tupleXTurn xs
at ZinkeMarencicUebung08.hs:42:21
Expected type: (xs, String)
Actual type: (String, String)
In the first argument of ‘fst’, namely ‘x’
In the expression: fst x
Quick fix
Replace:
(snd x,fst x) ++ (tupleXTurn xs)
with:
(snd x,fst x) : (tupleXTurn xs)
Operator (++) is for concatenating two lists. For prepending an element to a list you should use (:).
You should also notice that your function is not able to match [] in your function definition. So you should have:
tupleXTurn :: [(String, String)]->[(String, String)]
tupleXTurn [] = []
tupleXTurn (x:xs) = (snd x,fst x) : (tupleXTurn xs)
Live demo
Improving the function
You can also relax the function type to:
[(a, b)] -> [(b, a)]
And finally, you can simply define your function in terms of map and swap (from Data.Tuple):
tupleXTurn :: [(a, b)]->[(b, a)]
tupleXTurn = map swap
Live demo
The error is because you're trying to concatenate a tuple and a list with ++. This is used when you want to join two lists together, but you want to prepend an element to the front of the list, so you should use the : operator instead:
tupleXTurn (x:xs) = (snd x, fst x) : tupleXTurn xs
A more idiomatic way would be to define a function to swap a single tuple then use map:
swap :: (a, b) -> (b, a)
swap (a, b) = (b, a)
tupleXTurn :: [(String, String)] -> [(String, String)]
tupleXTurn xs = map swap xs
This also avoids the problem of having to handle the empty list, as of right now your function would also error if given an empty list as its argument since it doesn't match the pattern (x:xs), but map already handles this for you.
FYI: swap is already defined in Data.Tuple, so you don't even need to define it yourself.

How can say that a function input should be a list?

I need to prototype a function, saying toList, which takes a list as its only argument, and returns a list of lists (whose type is the same that the original list).
For example [Char] will give us a [[Char]].
I've tried :
(List a) => a -> [a]
which can't work as the Class List does not exist.
How should I do then ?
Thanks in advance
Try this:
f :: [a] -> [[a]]
Tails is a good example of this:
tails :: [a] -> [[a]]
Usage:
tails [1,2,3] == [[1,2,3], [2,3], [3],[]]