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.
Related
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!
I got a problem that needs to turn a list of tuples into a flattened list for example:
[(1,2), (3,4), (5,6)] can be turned into [1,2,3,4,5,6]
I have tried to write a function like this:
fun helper2(nil,b) = []
| helper2(a,nil) = []
| helper2(a::l1,b::l2) =l1::l2
fun flatten2 [] = []
| flatten2 ((a,b)::tl) = helper2(a,b)
It shows:
val flatten2 = fn : ('a list * 'a list list) list -> 'a list list
And when I tried to run it using command flatten2[(1,2),(3,4),(5,6)];
It will give me the following error message:
stdIn:1.2-1.29 Error: operator and operand do not agree [overload conflict]
operator domain: ('Z list * 'Z list list) list
operand: ([int ty] * [int ty]) list
in expression:
flatten2 ((1,2) :: (3,4) :: (<exp>,<exp>) :: nil)
My questions are:
Why SML see the a and b values as lists, not just simply a and b
How can I revise my code so SML can see a and b as 'a and 'b not lists
How to make this code work the way it should be?
Thanks
First question: As to why the type comes out as ('a list * 'a list list) it's because type inference is looking at this part of the code:
| helper2(a::l1,b::l2) =l1::l2
^^
here
Keep in mind that the type of the "cons" (::) operator is 'a -> 'a list -> 'a list, it is gluing a single element onto a list of that same type of element. So SML has concluded that whatever l1 and l2 are, the relationship is that l2 is a list of whatever l1 is.
fun helper2(nil,b) = []
Says that a must be a list because nil has type 'a list. Therefore, l2 has to be a list of lists (of some type 'a).
Question 2 and 3: I'm not quite sure how to correct the code as it is written. I'd probably write something like this:
fun helper2 [] accum = List.rev accum
| helper2 ((a,b)::tl) accum = helper2 tl (b :: a :: accum);
fun flatten2 list = helper2 list [];
helper2 does all of the dirty work. If the input list is empty then we're all done and we can return the reversed accumulator that we've been building up. The second case is where we actually add things to the accumulator. We pattern match on the head and the tail of the list. This pattern match means that the input has type ('a * 'a) list (a list of tuples where both elements are the same type). In the head, we have a tuple and we name the first and second element a and b, respectively. We prepend a then b onto the accumulator and recursively call helper2 on the tail of the list. Eventually, we'll chew through all the elements in the list and then we'll be left with just the accumulator -- which, recall, has all the elements but in the reverse order. Calling List.rev reverses the accumulator and that's our answer.
And when I load and run it I get this:
- flatten2 [(1,2), (3,4), (5,6)];
val it = [1,2,3,4,5,6] : int list
Why SML see the a and b values as lists, not just simply a and b
Chris already answered this in-depth.
You're passing a as the first argument to helper2, which expects a list as its first argument. And you're passing b as the second argument to helper2, which uses its second argument, b::l2, also a list, as the tail of a list where a is the head. So b must be a list of those lists.
This doesn't make any sense, and is most likely a consequence of confusing syntax: You are passing in what you think of single elements a and b in flatten2, but when you deal with them in helper2 they're now lists where the heads are called a and b. Those are not the same a and b.
How can I revise my code so SML can see a and b as 'a and 'b not lists
You could ditch the helper function to begin with:
fun flatten2 [] = []
| flatten2 ((a,b)::pairs) = a :: b :: flatten2 pairs
The purpose of having a helper function is so that it can accumulate the result during recursion, because this version of flatten2 uses a lot of stack space. It can do this with an extra argument so that flatten2 doesn't need to mention it:
This is the version Chris made.
How to make this code work the way it should be?
You can make this code in a lot of ways. Two ways using explicit recursion were mentioned.
Here are some alternatives using higher-order functions:
(* Equivalent to my first version *)
fun flatten2 pairs =
foldr (fn ((a,b), acc) => a :: b :: acc) [] pairs
(* Equivalent to Chris'es version *)
fun flatten2 pairs =
rev (foldl (fn ((a,b), acc) => b :: a :: acc) [] pairs)
(* Yet another alternative *)
fun concatMap f xs =
List.concat (List.map f xs)
fun flatten2 pairs =
concatMap (fn (a,b) => [a,b]) pairs
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'.
I'm very new on Haskell, and I'm trying the following:
To obtain [1,2,3] from [[1,2,3],[4,5,6]]?
example :: [[a]] -> [a]
example [] = []
example [x:xs] = [x]
This example is returning [1] when input is [[1,2,3]] and if I add an other element in the main List, like [[1,2,3],[3,4,5]] then I have a Non-exhaustive pattern function.
You are quite close. In fact what you here want is some sort of "safe" head.
A list [a] has two constructors:
the empty list [], you cover this in the first case; and
the "cons" (x:xs).
It looks like you cover that in the second case, but in fact you do not: you put the pattern within square brackets. As a result, Haskell interprets your pattern as [(x:xs)]. So it thinks you match a singleton list (a list with one element), and that x is the head of the sublist, and xs the tail of the sublist.
In fact you want to cover (x:xs). If we use this pattern, there is another problem: x is the head of the list, so it has type [a]. Therefore we should return x, not [x], since in the latter case, we would wrap the sublist back in a list.
So a correct function is:
example :: [[a]] -> [a]
example [] = []
example (x:_) = x -- round brackets, x instead of [x]
Note that since we are not interested in the tail here, we use an underscore _. If you compile with all warnings (-Wall, or more specific -Wunused-matches) Haskell will otherwise complain about the fact that you declare a variable that you do not use.
Generalizing to a safeHead function
We can generalize this to some sort of generic safeHead :: b -> (a -> b) -> [a] -> b function:
safeHead :: b -> (a -> b) -> [a] -> b
safeHead d _ [] = d
safeHead _ f (x:_) = f x
Here we thus pass three arguments to safeHead: a value (of type b) we should return in case the list is empty; a function to post-process the head (type a -> b), and the list to process. In that case the example is equivalent to:
example :: [[a]] -> [a]
example = safeHead [] id
But we can also return a Maybe [a] here:
example2 :: [a] -> Maybe a
example2 = safeHead Nothing Just
I am trying to write a remove function, so that a user can type remove 'd' ["abc", "dc", "ad"] and get the output ["abc", "c", "a"].
My code is:
remove :: Eq a => a -> [[a]] -> [[a]]
remove a (x:xs) = filter (not.a) (x:xs)
But I get the following error message:
Occurs check: cannot construct the infinite type: a = [a] -> Bool
When generalising the type(s) for `remove'
What does the error message mean, and how can I change the second line so it works?
The type of filter is
filter :: (a -> Bool) -> [a] -> [a]
so the first argument you pass to filter must be a function from the element-type of the list to Bool. In
remove :: Eq a => a -> [[a]] -> [[a]]
remove a (x:xs) = filter (not.a) (x:xs)
you say
a has type a, and the list has type [[a]], i.e. the list-element type is [a], and
not . a, the first argument to filter, has type [a] -> Bool.
Together, these imply
a = [a] -> Bool
but that is an infinite type.
You probably meant something like filter (not . (a `elem`)), or equivalently filter (a `notElem`), if the filter is meant to work on the outer list, or map (filter (/= a)) if you want to remove an element from each of the contained lists.
You state that the argument a is any type that supports equality.
But you then use it in a boolean expression: not . a.
The type of not is :: Bool -> Bool, so a must be of type Bool. But you already said that no, it was of type Eq t => t.
So that's a type error.
I think you mean to filter all elements that do not equal a, which would be:
remove a xs = filter (/= a) xs
However, your input is also a nested list, so you have to map the filter over the inner elements:
remove a xs = map (filter (/= a)) xs