I've just started to learn Haskell and I am trying to write a simple function that takes a list of strings and reverses each string in the list:
revComp :: [String] -> [String]
revComp [] = []
revComp [x] = [] ++ [reverse x]
revComp (x:xs) = revComp [xs]
When I try to load my code in GHCI, I get an error:
Couldn't match expected type `Char' with actual type `[Char]'
Expected type: String
Actual type: [String]
Could anyone explain what and where my problem is? Thanks very much.
The first three lines are fine. Your type signature is correct, the second line is correct, and so is the third. (However, [] ++ [reverse x] is the same as [reverse x].)
The fourth line, however, is wrong. Not only do you not use x at all on the right-hand side, but you have a type error: revComp [xs] calls revComp with a single-element list that has xs as its only element. Here, x is the first element of the list, and xs is the rest of the list. So, since xs has the type [String], [xs] has the type [[String]], but revComp takes a [String]! You want to reverse x, and prepend that to the result of reversing the rest of the list.
You can use revComp xs to reverse each string in the rest of the list, and (:) to prepend a value to a list (with the same syntax seen in the x:xs pattern you used on the left-hand side). That should be enough information for you to fix the last line. This makes the third line redundant, by the way, since [x] is just x:[].
ehird's answer is really complete, but I wanted to point out -- as a reference -- the "good/shorter" way to implement that function in real code, since you're new.
It can be defined as the partial application of map to reverse:
Prelude> let revComp = map reverse
Prelude> revComp ["olleh", "dlrow"]
["hello","world"]
It results in a function revComp :: [[a]] -> [[a]] (and not [String] -> [String] since both map and reverse work on any type of lists) that maps reverse to every element of the input list, returning the list of results.
The third line might not be required even with your example. The edge case (terminating condition) can be only the empty list. You can skip the condition for the single element.
revComp :: [String] -> [String]
revComp [] = []
revComp (x:xs) = reverse x : revComp xs
Don't know if there is a CS term for this. Someone in the community can add that information.
A few more ways to do the same thing:
revstr [] = []
revstr (x:xs) = reverse x : revstr xs
revstr2 [] = []
revstr2 (x:xs) = [reverse x] ++ revstr2 xs
revstr3 xs = map reverse xs
revstr4 = map reverse -- map takes 2 arguments ;)
revstr5 xs = foldl step [] xs
where step acc x = acc ++ [reverse x]
revstr6 xs = foldr step [] xs
where step x acc = reverse x : acc
Related
You have a list with N elements
You only want to print elements that are not circular permuations of other elements of the same list
To check if two strings are the circular permutations of each other I do this, which works fine :
string1 = "abc"
string2 = "cab"
stringconc = string1 ++ string1
if string2 `isInfixOf` stringconc
then -- it's a circular permuation
else -- it's not
Edit : As one comment pointed that out, this test only work for strings of the same size
Back to the real use case :
checkClean :: [String] -> [String] -> IO String
checkClean [] list = return ""
checkClean (x:xs) list = do
let sequence = cleanInfix x list
if sequence /= "abortmath"
then putStr sequence
else return ()
checkClean xs list
cleanInfix :
cleanInfix :: String -> [String] -> String
cleanInfix seq [] = seq
cleanInfix seq (x:xs) = do
let seqconc = x ++ x
if seq `isInfixOf` seqconc && seq /= x
then "abortmath"
else cleanInfix seq xs
However this just outputs... nothing
With some research I found out that sequence in checkClean is always "abortmath"
Also I'm not quite comfortable with this "flag" abortmath, because if by any chance one element of the list is "abortmath", well..
For example :
if I have a list composed of :
NUUNNFFUF
FFUFNUUNN
I should write
NUUNNFFUF
I guess you call your initial code (question) with something like that:
result = ["NUUNNFFUF", "FFUFNUUNN"]
main = do
checkClean result result
It won't print anything because:
the first call of cleanInfix has the arguments following arguments: "NUUNNFFUF" and ["NUUNNFFUF", "FFUFNUUNN"]
in cleanInfix, since seq == x you have a recursive call with the following arguments: "NUUNNFFUF" and ["FFUFNUUNN"]
now, "NUUNNFFUF" is a real permutation of "FFUFNUUNN": cleanInfix returns "abortmath", and checkClean returns ()
then you have a recursive call of checkClean with following arguments: "FFUFNUUNN" and ["NUUNNFFUF", "FFUFNUUNN"]
again, "FFUFNUUNN" is a real permutation of "NUUNNFFUF": cleanInfix returns "abortmath", and checkClean returns ()
this is the end.
Basically, x is a permutation of y and y is a permutation of x, thus x and y are discarded.
Your answer works, but it is horribly complicated.
I won't try to improve either of your codes, but I will make a general comment: you should (you really should) avoid returning a monad when you don't need to: in the question, checkClean just needs to remove duplicates (or "circular duplicates") from a list. That's totally functional: you have all the information you need. Thus, remove those dos, lets and returns!
Now, let's try to focus on this:
You have a list with N elements You only want to print elements that are not circular permuations of other elements of the same list
Why don't you use your initial knowledge on circular permutations?
isCircPermOf x y = x `isInfixOf` (y ++ y)
Now, you need a function that takes a sequence and a list of sequences, and return only the elements of the second that are not circular permutations of the first :
filterCircDuplicates :: String -> [String] -> [String]
filterCircDuplicates seq [] = []
filterCircDuplicates seq (x:xs) =
if seq `isCircPermOf` x
then removeCircDuplicates seq xs
else x:removeCircDuplicates seq xs
This pattern is well know, and you can use filter to simplify it:
filterCircDuplicates seq l = filter (\x -> !seq `isCircPermOf` x) l
Or better:
filterCircDuplicates seq = filter (not.isCircPermOf seq)
Note the signature: not.isCircPermOf seq :: String -> Boolean. It returns true if the current element is not a circular permutation of seq. (You don't have to add the list argument.)
Final step: you need a function that takes a list and return this list without (circular) duplicates.
removeCircDuplicates :: [String] -> [String]
removeCircDuplicates [] = []
removeCircDuplicates (x:xs) = x:filterCircDuplicates x (removeCircDuplicates xs)
When your list has a head and a tail, you clean the tail, then remove the duplicates of the first element of the tail, and keep this first element.
Again, you have a well known pattern, a fold:
removeCircDuplicates = foldr (\x acc -> x:filterCircDuplicates x acc) []
It removes the duplicates from right to left.
And if you want a one-liner:
Prelude Data.List> foldr (\x -> ((:) x).filter(not.(flip isInfixOf (x++x)))) [] ["abcd", "acbd", "cdab", "abdc", "dcab"]
["abcd","acbd","abdc"]
The wonders you can make with a pen and some paper...
So if anyone is interested here is how I solved it, it's probably badly optimised but at least it works (I'm just trying to learn haskell, so it's good enough for now)
-- cleanInfix function
cleanInfix :: String -> [String] -> [String] -> [String]
cleanInfix sequence [] cleanlist = cleanlist
cleanInfix sequence (x:xs) cleanlist = do
-- this is where I check for the circular permuation
let sequenceconc = x ++ x
if sequence `isInfixOf` sequenceconc
then cleanInfix sequence xs (delete x cleanlist)
else cleanInfix sequence xs cleanlist
-- checkClean Function
checkClean :: [String] -> [String] -> [String] -> [String]
checkClean [] listesend cleanlist = cleanlist
checkClean (x:xs) listesend cleanlist = do
-- The first delete is to avoid checking if an element is the circular permuation of... itself, because it obviously is... in some way
let liste2 = cleanInfix x (delete x listesend) cleanlist
checkClean xs (delete x listesend) liste2
-- Clean function, first second and third are the command line argument don't worry about them
clean first second third = do
-- create of the result list by asking user for input
let printlist = checkClean result result result -- yes, it's the same list, three times
print printlist -- print the list
So, I know, there is a built in function to reverse a list in Haskell, but I'm trying to write my own little function, just to practice some Haskell. I thought of the following code, which sadly is not working. Could you guys tell me what I did wrong?
rev :: [Int] -> [Int]
rev [] = []
rev [x] = last [x] : rev init [x]
If you want to do it efficiently, I'd recommend you use an accumulator:
rev :: [a] -> [a]
rev xs = go xs []
where
go :: [a] -> [a] -> [a]
go [] ys = ys
go (x:xs) ys = go xs (x:ys)
The function go, at each step, removes one element from the first list xs and prepends it to the second list ys. This is similar to popping from a stack and pushing to another stack -- which reverses the order.
Since we only use a constant amount of time at each recursive call, we get O(n) complexity, where n is the list length.
Instead, if at each recursive call we use last or append with ... ++ [x], we pay O(n) for each call, hence O(n^2) overall.
You almost had it.
rev :: [Int] -> [Int]
rev [] = []
rev x = last x : rev (init x)
Explanation: [x] was a list containing x, whereas you want to operate directly with x
ps. here's the documentation for Data.List. And remember to import Data.List
Well, you could do something like this:
rev :: [Int] -> [Int]
rev [] = []
rev (x:l) = (rev l) ++ [x]
The 3rd line takes the first element from the list and then creates a list containing only that element. This is appended to the result of the recursion rev l call.
I'm working my way through the NLPWP Book, and I'm at the chapter that deals with recursive functions. A recursive function for computing bigrams looks like this:
bigram :: [a] -> [[a]]
bigram [] = []
bigram [_] = []
bigram xs = take 2 xs : bigram (tail xs)
And if I run it on the wordlist = ["colorless", "green", "ideas", "sleep", "furiously"] I get this:
bigram chomsky
[("colorless","green"),("green","ideas"),("ideas","sleep"),("sleep","furiously")]
The exercise says:
A skip-bigram is any pair of words in sentence order. Write a function skipBigrams that extracts skip-bigrams from a sentence as a list of binary tuples, using explicit recursion. Running your function on ["Colorless", "green", "ideas", "sleep", "furiously"] should give the following output:
Prelude> skipBigrams ["Colorless", "green", "ideas", "sleep", "furiously"]
[("Colorless","green"),("Colorless","ideas"),("Colorless","sleep"),("Colorless","furiously"),("green","ideas"),("green","sleep"),("green","furiously"),("ideas","sleep"),("ideas","furiously"),("sleep","furiously")]
Here is the definition I've tried:
skipBigram [] = []
skipBigram [_] = []
skipBigram (x:xs) = [(x, (head xs)), (x, skipBigram xs)]
But I'm getting the following error:
Occurs check: cannot construct the infinite type: t ~ [(t, t)]
Relevant bindings include
xs :: [t] (bound at :3:15)
x :: t (bound at :3:13)
skipBigram :: [t] -> [(t, t)] (bound at :1:1)
In the expression: interactive:IHaskell384.skipBigram xs
In the expression: (x, interactive:IHaskell384.skipBigram xs)
Which, new to Haskell as I am, I don't understand in the slightest. What is an infinite type? A relevant binding?
How should I define skipBigram to resolve this compile-time error?
you get this because your result is a list-of-pairs, where the second-part of the first item in that list is some element and the second-part of the second item in your result list is, whatever you are trying to give back (you use recursion here so it will have the same type) - so you say:
my result is a list-of-tuples, but part of those tuples is the result-type itself
that is what the error tells you
here are some details:
look at your last line
skipBigram (x:xs) = [(x, (head xs)), (x, skipBigram xs)]
you have a list of tuples on the right side so it's type will be like (based on the first element of the result list):
skipBigram :: [a] -> [(a,a)]
but in the second-item you have (x, skipBigram xs) meaning it will have the type (a, [(a,a)]) (remember the type of skipBigram xs is the above part).
and so - comparing the second parts of the tuples - you have a ~ [(a,a)] which produces your error because somehow the type a should be the same as [(a,a)] which you could expand in all eternity ;)
now to the algorithm itself:
It will not work like this - you somehow have to get all combinations and to do this you have to work with the items in the list.
Usually you either do this with list-comprehensions or with the do-notation of the list-monad.
To get going think about this:
f [] = [[]]
f (x:xs) =
let xss = f xs
in [ x:xs | xs <- xss ] ++ xss
test it and play with it in ghci - you will have to combine this with what you got somehow
(ok recursion.ninja ^^ spoiled your fun - I'll let this here anyway if you don't mind)
Try this definition:
skipBigram :: [a] -> [(a,a)]
skipBigram [] = [] -- nothing to do with an empty list
skipBigram (x:xs) = [(x,y) | y <- xs] ++ skipBigram xs
Your skipBigram function is generating all the "2-tuple left-to-right combinations" of words in the list. We can capture this concept with a simple list comprehension in the recursive definition. By recursively concatenating the simple list comprehensions, we gain the desired result list.
The infinite type error is complaining about your use of lists. Your function should have the type [a] -> [a] -> [(a, a)], but when GHC tries to infer your function's type, it gets that a = [a], an infinite type. Relevant bindings are just the types of other variables which may be causing the error.
However, even ignoring the type errors, your function will not do what you want at all. Firstly, your function will always return a list of length two, because you have explicitly constructed the list. Also, the result would include ("Colorless", "Colorless"), because (x, head xs) is the same here as (x, x).
Instead, try this solution
skipBigram :: [a] -> [(a, a)]
skipBigram [] = []
skipBigram (x:xs) = map (x,) xs ++ skipBigram xs
For this function to work, you will need to put the line
{-# LANGUAGE TupleSections #-}
at the beginning of your file.
i have the following two functions in haskell:
plusList :: [[Int]] -> [Int]
plusList [xs ys] = add xs + plusList [ys]
plusList [[]] = 0
add::[Int] -> Int
add (x:xs) = x + add xs
add [] = 0
so, i think i have the error in plusList [xs ys] = add xs + plusList ys
My idea was to go through the set of the sets, namely [[Int]], by taking the first List xs, apply "add" on it and after that, call the second list ys recursively with "plusList ys"
I am new in haskell, can I do that? And if no, why?
You can certainly do what you want in Haskell, but your syntax is wrong. Your add function is correct, but plusList is not. In particular, the syntax [xs ys] makes no sense as a pattern to Haskell, you probably want
plusList (xs:ys) = add xs + plusList ys
Notice how this is exactly the same pattern as with add? Although, from your type signature it's hard to tell what exactly you want. The type says return a list of Int, but your function body says to just return an Int. If you want the former, you can achieve it with
plusList (xs:ys) = add xs : plusList ys
But this is exactly map add! If instead you want the latter, use the first snippet from above.
The second problem you have is
plusList [[]] = 0
This is a perfectly valid and legal line of Haskell code, but it won't do what you want. You see, there's a difference between [] :: [[Int]] and [[]] :: [[Int]]. The first is an empty list of lists of Ints, the second is a list containing an empty lists of Ints. If you run length ([] :: [[Int]]), you'll get 0, but for length ([[]] :: [[Int]]) you'll get 1!. Instead, just do
plusList [] = 0
Again, this is exactly like the pattern in add. If you want plusList to return [Int] instead, this line should just be
plusList [] = []
So the two versions we have are
plusList :: [[Int]] -> Int
plusList (xs:ys) = add xs + plusList ys
plusList [] = 0
And
plusList :: [[Int]] -> [Int]
plusList (xs:ys) = add xs : plusList ys
plusList [] = []
-- or just
-- plusList xs = map add xs
There is an easier way to do this, though. Firstly, add is merely the built-in sum function but specialized to Ints. However, the built-in sum is not very efficient due to the fact that it uses foldl. Instead, you can implement a faster variant with
add :: [Int] -> [Int]
add xs = foldr (+) 0 xs
The foldr and foldl functions generalize the kind of recursion you have used, since it is such a common pattern in functional programming. Instead of operating on the entire list, you provide a function for combining the next value and an accumulator together, an initial accumulator value, and the values to accumulate. In your case, the accumulator has the same type as your values, which is pretty common. The difference between foldl and foldr is subtle, their implementations look pretty similar, but Haskell's laziness means that foldl can have space leaks and efficiency problems (there's plenty of explanations out there as to why, look it up when you get there).
Additionally, if you want to sum a list of lists, you can do it using higher order functions with simply
plusList = add . map add
Nothing extra is needed, no patterns to match, much less syntax to get wrong.
I am working on a function in Haskell that will take one list and divide it into two evenly sized lists. Here is what I have:
split (x:y:xs) = split2 ([((length(x:y:xs) `div` 2)-2) : x ++ y] : [xs])
split2 (x:xs:[y:ys]) = split2 ((x-1) : [xs] ++ y : [ys])
split2 (0:xs:[y:ys]) = (xs:[y:ys])
The function takes the first two elements of a list, and puts them together into list #2 and appends the first list as a second element. It then gets the length of the list, and divides it by two to find out how many times to run taking into account the fact that it already removed two elements from the first list. It then takes those two pieces of information and puts it into split2, which takes another element from the first list and appends it to the second list in the first element, also it counts down 1 from the number of runs and then runs again.
Problem is, when I run it I get this:
Functions.hs:19:49:
Occurs check: cannot construct the infinite type: t0 = [t0]
In the first argument of `(:)', namely `(y)'
19 refers to line 2, the first split2 function. Not exactly sure how to go about fixing this error. Any ideas?
It's hard to know where to start...
Let's define functions from ever larger chunks of the expression in split2.
f1 (x:y:xs) = (length(x:y:xs) `div` 2)-2
f1 :: [a] -> Int
Ok, so the argument is a list of something, and it returns an Int
f2 (x:y:xs) = ((length(x:y:xs) `div` 2)-2) : x
f2 :: [[Int]] -> [Int]
Here, the length Int is being cons'd with x, so x must be [Int], so (x:y:xs) must be [[Int]]. We can also infer that y has the same type as x, and xs is a list of things of the same type; [[Int]]. So the x ++ y will also be [Int].
So, [xs] will have type [[[Int]]]. Now, we wrap the result in a list constructor, and cons it with [xs]:
f3 (x:y:xs) = [((length(x:y:xs) `div` 2)-2) : x ++ y] : [xs]
f3 :: [[Int]] -> [[[Int]]]
I'm guessing you didn't expect the argument to be a list of lists of lists of Ints.
Now, if we look at split2, the argument pattern (x:xs:[y:ys]) implies that it is of type:
split2 :: [[a]] -> b
x :: [a]
xs :: [a]
y :: a
ys :: [a]
The rhs of the first definition of split2 tries to construct a new list by concatenating (x-1) : [xs] and y : [ys]. However, if we substitute the types into the y : [ys], we find:
y : [ys] :: a : [[a]]
But since (:) :: a -> [a] -> [a], this means that [[a]] must be the same type as [a], or a must be a list of itself, which is not possible.
The (x-1) is also badly typed, because it attempts to subtract one from a list.
I can't tell if you want to split the lists into even and odd elements, or into first and second halves.
Here are two versions that split into the first and second halves, rounding down (RD) or up (RU) if the length is odd:
splitRD xs = splitAt (length xs `div` 2) xs
splitRU xs = splitAt ((length xs + 1) `div` 2) xs
Here's a version that splits the list into even and odd elements:
splitEO [] = ([], [])
splitEO [e] = ([e], [])
splitEO (e:o:xs) = (e:es, o:os) where (es, os) = splitEO xs
Few suggestions
Write types to all the functions. It makes the code more readable and also helps catching errors.
The type of ++ is [a] -> [a] -> [a] and you are adding length of a list along with elements. Since list has to be of uniform type and length returns Int type, so compiler infers type of split as
[[Int]] -> t (assuming split2 returns type t).
When you pass ([((length(x:y:xs)div2)-2) : x ++ y] : [xs]) to split2.
xs is of type [[Int]] which means
[xs] is of type [[[Int]]]
, so compiler infers type of split2 to [[[Int]]] -> t.
Now in the definition of split2
split2 (x:xs:[y:ys]) = split2 ((x-1) : [xs] ++ y : [ys])
ys is of type [[Int]], so y is of type [Int]. xs is of type [[Int]], but you are doing [xs] ++ y, which means both [xs] and y should be of same type ( [a] for some a).
Since you have not provided any types compiler is totally confused how to infer such type.
If you simply want to split the list into two equal parts why not do something more simpler like
split3 :: [a] -> ([a], [a])
split3 [] = ([],[])
split3 [x] = ([x],[])
split3 (x:y:xs) = let (xs',ys') = split3 xs in (x:xs',y:ys')
You seem to be passing state around in a list instead of as values to a function, which creates problems when it seems to the compiler as though you're creating a list of heterogenous values, whereas lists in Haskell are supposed to be of homogenous type.
Instead of
split2 (0:xs:[y:ys])
you should pass the different arguments/values to the function separately like this
split2 n xs (y:ys)
The functionality you're looking for is also reproduced in standard library functions.
halveList xs = splitAt (length xs `div` 2) xs
In Haskell, the elements of a list need to be all of the same type. In your function the lists contain a mixture of Ints, elements of the original list, and sublists of the original list, all of which are probably different types.
You also have some confusion about how to append lists and elements. x ++ y can only be used when x and y are themselves lists, while x : y can only be used when y is a list and x is an element of a list; to make a new list containing x and y as elements instead use [x, y] (although x:[y] also works). Similarly [xs] ++ y needs to be xs ++ [y] instead.
Without changing your basic algorithm, the simplest solution is probably to let split2 take 3 separate arguments.
split (x:y:xs) = split2 ((length(x:y:xs) `div` 2)-2) [x,y] xs
split2 n xs (y:ys) = split2 (n-1) (xs++[y]) ys
split2 0 xs ys = [xs,ys]