I have written the code below to test whether a list is a Palindrome or not. To my surprise its not compiling with the error "No instance for (Eq a) arising from a use of == ....". My assumption is that the compiler does not know that leftHalf and rightHalf are lists.
isPalindrome :: [a] -> Bool
isPalindrome [] = False
isPalindrome xs = if (leftHalf == reverse rightHalf)
then True
else False
where leftHalf = take center xs
rightHalf = drop center xs
center = if even (length xs)
then (length xs) `div` 2
else ((length xs) - 1) `div` 2
1) How do I tell the compiler that leftHalf and rightHalf are lists?
2) How would I use pattern matching or other haskell language features to solve this?
EDIT: Thank you all for your input. Special mention to Matt Fenwick for the documentation link and Duri for the elegant tip. I will write the final solutions below just in case
isPalindrome' :: (Eq a) => [a] -> Bool
isPalindrome' [] = False
isPalindrome' xs = if p then True else False
where p = leftHalf == rightHalf
leftHalf = take c xs
rightHalf = take c (reverse xs)
c = div l 2
l = length xs
isPalindrome' can be improved like Demi pointed out
isPalindrome'' :: (Eq a) => [a] -> Bool
isPalindrome'' [] = False
isPalindrome'' xs = if (reverse xs) == xs then True else False
In order to test if two lists are equal, it must be possible to test if the items in the list are equal. Therefore, your list of type [a] must ensure that a is an instance of Eq.
Also, as a matter of style:
x = if c then True else False
can be replaced with
x = c
Check out the Eq typeclass:
ghci> :i (==)
class Eq a where
(==) :: a -> a -> Bool
...
-- Defined in GHC.Classes
infix 4 ==
What you need is a type constraint on isPalindrome.
Also, this code
if (leftHalf == reverse rightHalf)
then True
else False
is unnecessarily long.
You should change your type to:
isPalindrome :: Eq a => [a] -> Bool
And this is really extraneous to find center, it's enough to just write xs == reverse xs - when you computing length xs you go through all the list and there is no economy.
Related
I am new to Haskell and its functions are a little confusing. The goal is to take a list comprehensions and obtain digits that is a palindrome and starts with the digit 3. I have successfully obtain a list comprehensions of palindrome, but got lost to how to also filter out the digit that does not start with 3.
I have something like this right now, what would be a better approach or way to think about this.
isPalindromeThatStartsWithDigit3 a = [ a | a<-[1..a], show a == reverse(show a) && filter ...]
As #luqui noted in the comments, Boolean conditions or guards are effectively filters in the context of list comprehensions. In the following code, I assume you wanted to enumerate all palindromes up to some value having some integral prefix.
isPalindrome :: (Show a) => a -> Bool
isPalindrome n = show n == reverse (show n)
startsWith :: (Eq a) => [a] -> [a] -> Bool
startsWith [] _ = True
startsWith _ [] = False
startsWith (x : xs) (y : ys) = x == y && startsWith xs ys
palindromesStartingWith :: (Integral a, Show a) => a -> a -> [a]
palindromesStartingWith x y = [ z | z <- [1..y],
isPalindrome z,
startsWith (show x) (show z) ]
For example:
*Main> palindromesStartingWith 1 1000
[1,11,101,111,121,131,141,151,161,171,181,191]
*Main> palindromesStartingWith 34 10000
[343,3443]
The documentation linked above describes list comprehensions and gives an explicit translation between list comprehensions and the list monad.
I'm trying to solve the 99 problems in Haskell, and for the 4th question, I have first tried such a solution
myLength :: [a] -> Int
myLength [] = 0
myLength ys = go 1 ys
where
go :: Int -> [a] -> Int
go n xs
| ( (take n xs) == (take (n+1) xs) ) = n
| otherwise = go (n+1) xs
However, the compiler gives the error:
Problem4.hs:10:8: error:
• No instance for (Eq a1) arising from a use of ‘==’
Possible fix:
add (Eq a1) to the context of
the type signature for:
go :: forall a1. Int -> [a1] -> Int
• In the expression: ((take n xs) == (take (n + 1) xs))
In a stmt of a pattern guard for
an equation for ‘go’:
((take n xs) == (take (n + 1) xs))
In an equation for ‘go’:
go n xs
| ((take n xs) == (take (n + 1) xs)) = n
| otherwise = go (n + 1) xs
|
10 | | ( (take n xs) == (take (n+1) xs) ) = n
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
As far as I understood, the reason for the error it that when we try to compare the lists returned from (take n xs) and (take (n+1) xs), the compiler does not know the types of lists in advance, so it cannot compare them, and this is why it complains, so before this line, I need to tell the compiler that both return values are the same type, and the type is [a], but how can we do that ?
A confusion: when we specify the type signature of go, we are explicitly fixing the what is the type of xs, i.e so shouldn't the list that is return by the function take have the same type, namely [a], hence shouldn't the compiler be able to compare them ?
Edit:
Note that, I have another function in the definition of a function, and there are lots of things that are different from the question that is marked as duplicate, and as you can observe, the given answer to that question does not fully solves this question.
What you need is instance contexts (here Eq a), which is indicated by =>:
myLength :: Eq a => [a] -> Int
myLength [] = 0
myLength ys = go 1 ys
where
go :: Eq a => Int -> [a] -> Int
go n xs
| ( (take n xs) == (take (n+1) xs) ) = n
| otherwise = go (n+1) xs
But this is not a proper answer to the question #4, because it adds an additional constraint to the function.
EDIT: For the question "Shouldn't every list be equality comparable?":
Lists are comparable iff their elements are comparable. For example, functions, Kleisli arrows, WrappedArrows are not equality comparable, so aren't lists of them.
{-# Language ScopedTypeVariables #-}
myLength :: forall a. Eq a => [a] -> Int
myLength [] = 0
myLength ys = go 1 ys
where
go :: Int -> [a] -> Int
go n xs
| take n xs == take (n+1) xs = n
| otherwise = go (n+1) xs
I want to write a polymorphic function that inputs two lists and tells me whether these two lists contain a common element. My attempt at writing this function is as follows:
overlaps :: (Eq a) => [a] -> [a] -> Bool
overlaps x:xs y:ys
| x `is_element_of` ys = True
| otherwise = False
where
is_element_of :: (Eq a) => a -> [a] -> Bool
is_element_of e list = case list of
[] -> False
x: xs -> e == x || e `is_element_of` xs
However this isn't working... Is it possible to pattern match against two lists? Is this a possible way of writing this function?
Your function is_elem_of already exists in the Data.List package as elem. Using that, overlaps is easy to write.
overlaps [] _ = False
overlaps (x:xs) ys = x `elem` ys || overlaps xs ys
As you can tell, it is possible to pattern match on lists. If you want to write the function without pattern matching on lists, you can use the foldr function.
overlaps xs ys = foldr (\x acc -> x `elem` ys || acc) False xs
I think you would want something like this (untested):
overlaps :: (Eq a) => [a] -> [a] -> Bool
overlaps [] _ = False
overlaps _ [] = False
overlaps (x:xs) list = x `myelem` list || overlaps xs list
myelem :: (Eq a) => a -> [a] -> Bool
myelem _ [] = False
myelem x (y:ys) = x == y || myelem x ys
AFAIK using the pattern matching appropach is more idiomatic.
Say I wanted to remove all zeros at the end of a list:
removeEndingZeros :: (Num a, Eq a) => [a] -> [a]
removeEndingZeros (xs ++ [0]) = removeEndingZeros xs
removeEndingZeros xs = xs
This does not work because of the (++) operator in the argument. How can I determine the end of a list through pattern-matching?
There is a function in Data.List to do this:
dropWhileEnd :: (a -> Bool) -> [a] -> [a]
dropWhileEnd p = foldr (\x xs -> if p x && null xs then [] else x : xs) []
So you can drop the trailing zeros with
dropWhileEnd (== 0)
Another, very similar, function can be implemented like this:
dropWhileEnd2 :: (a -> Bool) -> [a] -> [a]
dropWhileEnd2 p = foldr (\x xs -> if null xs && p x then [] else x : xs) []
dropWhileEnd2 p has exactly the same semantics as reverse . dropWhile p . reverse, but can reasonably be expected to be faster by a constant factor. dropWhileEnd has different, non-comparable strictness properties than the others (it's stricter in some ways and less strict in others).
Can you figure out circumstances under which each can be expected to be faster?
Is there any library function in Haskell that'll allow me to check if a list is ordered consecutively? eg. [1,2,3,4] is valid, [1,2,3,10] is invalid.
Basically I can have a list that ranges anywhere between 3 to 5 elements and I'm trying to check if that list is ordered consecutively.
My Attempt (I'm not sure if this is the right way to approach it, seems to be way too much repetition)
isSucc:: [Integer] -> Bool
isSucc[] = True
isSucc(x:y:zs) =
if (x+1) == y
then True && isSucc(y:zs)
else isSucc(y:zs)
After I have this function working, I'm planning on using it to filter a lists of lists (Keep the list inside the list only and only if it is ordered consecutively)
You can use the trick zipWith f xs (drop 1 xs) to apply f to consecutive pairs of list elements. (Notice drop 1 rather than tail, because the latter fails if the list is empty!)
If you replace f with <= you'll get a list of Bool values. Now see whether they're all True.
isSucc xs = and $ zipWith (<=) xs (drop 1 xs)
There's no standard function for that.
Here's a fixed version of your function, making it generic, removing the redundant conditions and adding the missing ones:
isSucc :: (Enum a, Eq a) => [a] -> Bool
isSucc [] = True
isSucc (x:[]) = True
isSucc (x:y:zs) | y == succ x = isSucc $ y:zs
isSucc _ = False
I prefer to use a little more readable solution than one that has been offered by MathematicalOrchid.
First of all we will define the utilitarian function pairwise that might be useful in many different circumstances:
pairwise xs = zip xs $ tail xs
or in more modern way:
import Control.Applicative ((<*>))
pairwise = zip <*> tail
and then use it with the other combinators:
isSucc xs = all (\(x,y) -> succ x == y) $ pairwise xs
There is another way,
isOrdered :: (Enum a, Eq a) => (a -> a -> Bool) -> [a] -> Bool
isOrdered op (a:b:ls) = op a b && isOrdered op (b:ls)
isOrdered op _ = True
Thus,
isSucc = isOrdered ((==) . succ)
If you want to check that all consecutive differences are equal to one, you can use
isIncreasingByOne :: (Eq a, Num a) => [a] -> Bool
isIncreasingByOne = all (==1) (zipWith (-) (tail xs) xs)
This works for numeric types (hence the Num a constraint), including Float and Double. It's also easy to adapt if you want to check that a sequence is increasing by more than 5 at a time, say.
-- This checks if ordered
isordd:: [Int] -> Bool
isordd [] = True
isordd (x:y:xs)
| x > y = False
| lengh xs == 0 = True
| otherwise = isordd (y:xs)
-- This calculates the length of the list
lengh::[Int]->Int
lengh [] = 0
lengh (x:xs) = 1+lengh xs