Why can't I pattern match on the concatenation function (++) in Haskell? - haskell

I'm trying to match **String Newline String** pattern in a function Split.
split::String -> [String]
split[] = []
split (x++'\n':xs) = [x]++split(xs)
I'm getting this error:
Parse error in pattern: x ++ ('\n' : xs)
What am I doing wrong here?
I know there are other ways of achieving the same result but I'd like to understand what wrong with this pattern. I'm fairly new to Haskell BTW.

One problem (as I understand it) is that ++ is not a constructor of the list data type the way : is. You can think of the list data type being defined as
data [a] = [] | a : [a]
Where : is a constructor that appends elements to the front of a list. However, ++ is a function (defined in the documentation here: http://hackage.haskell.org/package/base-4.8.1.0/docs/src/GHC.Base.html#%2B%2B) as
(++) :: [a] -> [a] -> [a]
(++) [] ys = ys
(++) (x:xs) ys = x : xs ++ ys
We could define our own data type list like
data List a = Empty | Cons a (List a)
That would mimic the behavior of our familiar list. In fact, you could use (Cons val) in a pattern. I believe you could also define a type with a concat constructor like so
data CList a = Empty | Cons a (CList a) | Concat (CList a) (CList a)
Which you could use to lazily concatenate two lists and defer joining them into one. With such a data type you could pattern match against the Concat xs ys input, but you that would only work on the boundary of two lists and not in the middle of one.
Anyway I'm still fairly new to Haskell myself but I hope this is on point.

Imagine you could. Then matching "a\nb\nc" could produce x = "a", xs = "b\nc" or x = "a\nb", xs = "c" and you'd need some ad hoc rule to decide which to use. Matching against functions is also impossible to reasonably implement in general: you need to find an x given f x, and there is no way to do this other than trying all possible x.

Related

How to define guards for different types of input than expected?

I am trying to transform an input list into a palindrome. For instance:
Input: [1,2,3]
Output: [1,2,3,3,2,1]
Basically I need to add a reversed list. My problem lies in the following:
palindrize::[a]->[a]
palindrize list | null list = []
palindrize (x:xs)=(x:xs)++revert(x:xs) where
revert list | null list =[]
revert (x:xs)= (revert xs):(x:[]) ---Here
How can I create a guard or a condition to when there is only one element create a list out of it (applying the (myelement:[]))? I would need somehow to say: revert can get a list or an element, if it's an element apply (element:[]) on it.
I think you make things too complex. First of all, Haskell has already a reverse :: [a] -> [a] that reverses the list, so we can make it:
palindrize :: [a] -> [a]
palindrize l = l ++ reverse l
Furthermore there is no need to use a guard here. We can perform pattern matching: this is safer since the compiler can then guarantee us that all patterns are covered. So we can write it like:
revert :: [a] -> [a]
revert [] = []
revert (x:xs) = (revert xs):(x:[]) -- error!
But this will result in a type error. Indeed, the (:) constructor has type (:) :: a -> [a] -> [a], but revert xs will result in type [a]. In situations like that one, it is best to use an accumulator: a parameter that we initialize for instance with the empty list, and then each recursive call update and at the end of the recursive process return. For example:
revert :: [a] -> [a]
revert = go []
where go xs [] = xs
go xs (x:ys) = go (x:xs) ys
First, you can not write list : element, nor list : (element : []) since types would not match: whatever is found at the left side of : must have the same type as the elements of the list found at the right side.
You can, however, append two lists using ++, like list ++ (element : []) or list ++ [element].
Second, to pattern match against a single element list, you can use
foo [] = ... -- empty list case
foo [x] = ... -- single element list case
foo (x1:x2:rest) = ... -- two elements or more case
If you prefer, the single element case can also be written foo (x:[]) = ....
Note that foo [] = ... is equivalent to foo list | null list = ..., but simpler. If possible, forget guards: they should only be used when pattern matching is not enough.

Haskell's span function

I'm relatively new to Haskell and I'm struggling to figure out a way to implement Haskell's span function. However, my problem is more general than that in that I don't know how to make a function return a list of lists or list of tuples containing the elements I want. My problem with a list of lists such as:
[[1],[2]]
is that I can't make the function add an element to the first list in the list of lists. I only know how to append another list to the list of lists.
In short, if you explain to me how to implement the span function, this all should hopefully come clear to me.
So I think what you're saying is that you know how to recursively append to a list by doing something like
foobar :: [x] -> [y]
foobar ( []) = []
foobar (x:xs) = {- ...stuff... -} : foobar xs
but you have no idea how to do that with two lists:
foobar :: [x] -> ([y], [z])
foobar (x:xs) = ???
In general, when the result isn't a list, but something that contains a list, you end up doing something like this:
foobar :: [x] -> ([y], [z])
foobar (x:xs) =
let
y = {- whatever -}
z = {- whatever -}
(ys, zs) = foobar xs -- The recursive call
in (y:ys, z:zs)
The same applies if, say, the result is a monadic action
foobar :: [x] -> IO [y]
foobar (x:xs) = do
y <- {- whatever -}
ys <- foobar xs
return (y:ys)
Note that this forces the function to not be lazy.
The general pattern I think you'll want to use here is the following:
span :: (a -> Bool) -> [a] -> ([a], [a])
span pred [] = ([], [])
span pred (x:xs) = if pred x then _ else _ -- fill in the blanks
where (prefix', suffix') = span pred xs
There are two non-obvious things there. First, note the pattern match in the where condition. This means that we're:
Calling span pred xs, which produces a pair of lists;
Pattern matching on this pair;
Naming the first and second element of the pair prefix' and suffix' respectively.
I suspect that step #2, the pattern match on the result of the recursive call, is something you might not have understood.
The second non-obvious thing is recursion. It's a tricky thing because, counterintutively, to solve a problem with recursion you need to assume that you've already solved it, but for the "wrong" argument--a tough step to picture yourself taking if you haven't solved it yet! But the trick is this:
Imagine you've actually already solved the problem, but for the tail of the list. That's what the prefix' and suffix' variables contain: a correct solution but for the wrong list--the tail of the one you're actually trying to solve for.
Given that (non)solution, how could you reuse it to arrive at a correct solution for your problem?

Little problems from a Haskell learner about filter & fold

This is my second day learning Haskell and I am stuck terribly by a problem.
I tried to solve the eighth problem in 99 Haskell questions
The problem is to write a function called "compress" which works like this:
>compress "aaaabbbbccccddddd"
"abcd"
>compress [1,1,1,1,2,3,4,4,4,4]
[1,2,3,4]
and here's what I wrote:
compress :: (Eq a) => [a] -> [a]
compress [] = []
compress x = filter ( (head x) `notElem` ( compress $ tail x ) ) x
The compiler said:
Couldn't match expected type a -> Bool' with actual type Bool'
In compress, I tried to recursively pick up new elements from end to head. (like backtracking maybe??)
Is my algorithm wrong?
Is there alternative way to implement the algorithm in a more readable way?
(Like: where to put parentheses? or $ )
Can someone kindly help me with it?
Thanks a lot.
Thanks to Lubomir's help, I corrected my code by :
compress'(x:xs) = x : compress' (dropWhile (== x) xs)
and it works!
And thanks everyone, I feel spoiled! You guys are so kind!
I'll keep on learning Haskell!
Is there alternative way to implement the algorithm in a more readable
way?
Yes.
import Data.List
compress :: Eq a => [a] -> [a]
compress = map head . group
map head . group is basically \xs -> map head (group xs). group xs will create a list of lists were all equal consecutive elements are grouped together in a list. map head will then take the heads of these lists discarding the rest as required.
The algorithm is basically fine, but it does not typecheck. The first argument to filter should be a function of type a -> Bool – for an element of the list it should tell you whether or not to throw it out. What you have is a single Bool value.
The second part of the function may be better implemented with a different pattern. This would allow you to drop the head and tail functions.
compress [] = []
compress (x:xs) = x : compress (filter (/= x) xs)
This pattern binds x to the first element of the list and xs is the tail of the list. The function should include x in the result and recursively call itself on filtered xs (with x removed from it).
EDIT: this function does not do what the problem requests. Only consecutive duplicates should be eliminated. This can be fixed by using dropWhile instead of filter and slightly modifying the predicate function.
Check the signature of filter:
Prelude> :t filter
filter :: (a -> Bool) -> [a] -> [a]
Note that the first argument must be a function. Now check the type of your expression within the paranthesis.
Prelude> :t notElem
notElem :: Eq a => a -> [a] -> Bool
Thus, notElem a b will return a value of type Bool.
Note: I think you might have misunderstood the problem statement. What is the expected output for aaabbbaaa?
I would argue it should be aba, as the problem is stated as
Eliminate consecutive duplicates of list elements.
(emphasize mine).

Haskell: Pattern Matching to combine String

I'm trying to write a function which adds single characters from a string to a list of strings, for instance
combine ", !" ["Hello", "", "..."] = ["Hello,", " ", "...!"]
I've tried this:
combine :: String -> [String] -> [String]
combine (y:ys) (x:xs) =
[x:y, combine ys xs]
A simple one would be
combine :: [Char] -> [String] -> [String]
combine [] _ = []
combine _ [] = []
combine (c:cs) (x:xs) = x ++ [c] : combine cs xs
Or even more simply using zipWith
combine :: [Char] -> [String] -> [String]
combine = zipWith (\c x -> x ++ [c])
I had to do a bit extra to get this to work. I'll break it down for you.
First, I specified the type of the function as [Char] -> [String] -> [String]. I could have used String for the first argument, but what you're operating on conceptually is a list of characters and a list of strings, not a string and a list of strings.
Next, I had to specify the edge cases for this function. What happens when either argument is the empty list []? The easy answer is to just end the computation then, so we can write
combine [] _ = []
combine _ [] = []
Here the _ is matching anything, but throwing it away because it isn't used in the return value.
Next, for the actual body of the function We want to take the first character and the first string, then append that character to the end of the string:
combine (c:cs) (x:xs) = x ++ [c]
But this doesn't do anything with cs or xs, the rest of our lists (and won't even compile with the type signature above). We need to keep going, and since we're generating a list, this is normally done with the prepend operator :
combine (c:cs) (x:xs) = x ++ [c] : combine cs xs
However, this is such a common pattern that there is a helper function called zipWith that handles the edge cases for us. It's type signature is
zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
It walks down both input lists simultaneously, passing the corresponding elements into the provided function. Since the function we want to apply is \c x -> x ++ [c] (turned into a lambda function), we can drop it in to zipWith as
combine cs xs = zipWith (\c x -> x ++ [c]) cs xs
But Haskell will let us drop arguments when possible, so we can eta reduce this to
combine :: [Char] -> [String] -> [String]
combine = zipWith (\c x -> x ++ [c])
And that's it!
When you want to combine lists element by element, it is usually a zip you are looking at. In this case, you know exactly how you want to combine the elements – that makes it a zipWith.
zipWith takes a "combining function" and then creates a function that combines two lists using said combining function. Let's call your "combining" function append, because it adds a characters to the end of a string. You can define it like this:
append char string = string ++ [char]
Do you see how this works? For example,
append 'e' "nic" = "nice"
or
append '!' "Hello" = "Hello!"
Now that we have that, recall that zipWith takes a "combining function" and then creates a function that combines two lists using that function. So your function is then easily implemented as
combine = zipWith append
and it will do append on each of the elements in order in the lists you supply, like so:
combine ", !" ["Hello", "", "..."] = ["Hello,", " ", "...!"]
You are close. There are a couple issues with what you have.
y has type Char, and x has type String which is an alias for [Char]. This means that you can add y to the top of a list with y : x, but you can't add y to the end of a list using the same : operator. Instead, you make y into a list and join the lists.
x ++ [y]
There must also be a base case, or this recursion will continue until it has no elements in either list and crash. In this case, we likely don't have anything we want to add.
combine [] [] = []
Finally, once we create the element y ++ [x] we want to add it to the top of the rest of the items we have computed. So we use : to cons it to our list.
combine :: String -> [String] -> [String]
combine [] [] = []
combine (x : xs) (y : ys) = (y ++ [x]) : (combine xs ys)
One note about this code, if there is ever a point where the number of characters in your string is different from the number of strings in you list, then this will crash. You can handle that case in a number of ways, bheklilr's answer addresses this.
kqr's answer also works perfectly and is probably the best one to use in practice.

When destructuring tuples in Haskell, where can the elements be used?

I am reading a tutorial that uses the following example (that I'll generalize somewhat):
f :: Foo -> (Int, Foo)
...
fList :: Foo -> [Int]
fList foo = x : fList bar
where
(x, bar) = f foo
My question lies in the fact that it seems you can refer to x and bar, by name, outside of the tuple where they are obtained. This would seem to act like destructuring parameter lists in other languages, if my guess is correct. (In other words, I didn't have to do the following:)
fList foo = (fst tuple) : fList (snd tuple)
where
tuple = f foo
Am I right about this behavior? I've never seen it mentioned yet in the tutorials/books I've been reading. Can someone point me to more info on the subject?
Edit: Can anything (lists, arrays, etc.) be destructured in a similar way, or can you only do this with tuples?
Seeing your edit, I think what your asking about is Pattern matching.
And to answer your question: Yes, anything you can construct, you can also 'deconstruct' using the constructors. For example, you're probably familiar with this form of pattern matching:
head :: [a] -> a
head (x:xs) = x
head [] = error "Can't take head of empty list"
However, there are more places where you can use pattern matching, other valid notations are:
head xs = case xs of
(y:ys) -> y
[] -> error "Can't take head of empty list"
head xs = let (y:ys) = xs
in y
head xs = y
where
(y:ys) = xs
Note that the last two examples are a bit different from the first to because they give different error messages when you call them with an empty list.
Although these examples are specific to lists, you can do the same with other data types, like so:
first :: (a, b) -> a
first tuple = x
where
(x, y) = tuple
second :: (a, b) -> b
second tuple = let (x, y) = tuple
in y
fromJust :: Maybe a -> a
fromJust ma = x
where
(Just x) = ma
Again, the last function will also crash if you call it with Nothing.
To sum up; if you can create something using constructors (like (:) and [] for lists, or (,) for tuples, or Nothing and Just for Maybe), you can use those same constructors to do pattern matching in a variety of ways.
Am I right about this behavior?
Yes. The names exist only in the block where you have defined them, though. In your case, this means the logical unit that your where clause is applied to, i.e. the expression inside fList.
Another way to look at it is that code like this
x where x = 3
is roughly equivalent to
let x = 3 in x
Yes, you're right. Names bound in a where clause are visible to the full declaration preceding the where clause. In your case those names are f and bar.
(One of the hard things about learning Haskell is that it is not just permitted but common to use variables in the source code in locations that precede the locations where those variables are defined.)
The place to read more about where clauses is in the Haskell 98 Report or in one of the many fine tutorials to be found at haskell.org.

Resources