I would like to put the 2 functions (color and check) into the most general form
Eq a => ....
But I don't know how to do that.
This is a very simple graph: each node has 2 neighbours, and any adjacent nodes must have different colors
color :: [(Int, Int)] -> [(Int, Int)] -> Bool
color x [] = True
color a ((x,y):rest) =
if check a x == check a y
then False
else color a rest
check :: [(Int, Int)] -> Int -> Int
check [] x = 999
check ((x,y):rest) p =
if x == p
then y
else check rest p
At the end, colors gives you True or False
Main> colors [('a',"purple"),('b',"green"),('c',"blue")] [('a','b'),('b','c'),('c','a')]
True
Main> colors [('a',"purple"),('b',"green"),('c',"purple")] [('a','b'),('b','c'),('c','a')]
False
Main> colors [('1',"purple"),('2',"green"),('3',"blue")] [('1','2'),('2','3'),('3','1')]
True
Main> colors [('1',"4"),('2',"5"),('3',"6")] [('1','2'),('2','3'),('3','1')]
True
Main> colors [('1',"4"),('2',"4"),('3',"5")] [('1','2'),('2','3'),('3','1')]
False
Any help is welcome (+ if you can fix x = 999 into False).
For starters, the reason you can't generalize the Int to an Eq a is because of the 999 hard-coded in check. If you just leave some random value in there, you must know its type, so you cannot generalize the function beyond that (well, in this particular case, you can generalize to Eq a, Num a, but not more).
So, the answer is to not use some arbitrary value, but instead wrap the return of check into a type that has a "failure" case, namely Maybe.
Renaming the variables to follow Haskell conventions, and giving the functions a bit more elucidating names, we get:
canColor :: Eq a => [(a, a)] -> [(a, a)] -> Bool
canColor _ [] = True
canColor xs ((x,y):rest) =
if findNeighbour xs x == findNeighbour xs y
then False
else canColor xs rest
findNeighbour :: Eq a => [(a, a)] -> a -> Maybe a
findNeighbour [] _ = Nothing
findNeighbour ((x,y):rest) z =
if x == z
then Just y
else findNeighbour rest z
The idea here is that findNeighbour returns Nothing if it can't find anything, or Just 23 if it finds 23 (or whatever it finds).
As it happens, findNeighbour is already defined: it's called lookup. So, you could rewrite your code as:
canColor :: Eq a => [(a, a)] -> [(a, a)] -> Bool
canColor _ [] = True
canColor xs ((x,y):rest) =
if lookup x xs == lookup y xs
then False
else canColor xs rest
Now, we note that you are basically checking a predicate against all items in a list. There's a function for this: all. So, we can shorten the code to:
canColor :: Eq a => [(a, a)] -> Bool
canColor xs = all (\(x, y) -> lookup x xs /= lookup y xs) xs
Related
I am still trying to better understand lists and tuples within Haskell, and I have come across a problem that I cannot seem to get.
I have a func with type:
func :: [String] -> [(String,String)] -> Bool
where i am trying to see if every value in the string list is present within our list of string tuples
For example input and output, let's say I call func ["Thomas","Jeff"] [("Thomas", "22"), ("Jeff", "16")] this should return true
Whereas if I try func ["Brian","Jeff"] [("Thomas", "22"), ("Jeff", "16")] this should return false
This is what I have so far:
func:: [String] -> [(String,String)] -> Bool
func [] ((y,z):ys) = True
func (x:xs) [] = False
func (x:xs) ((y,z):ys)
| x == y || x == z = func xs ((y,z):ys)
| otherwise = func (x:xs) ys
Can anyone see where I am going wrong?
First, we should collapse that [(String, String)] into a [String], since we're not making use of its pair structure:
flatten :: [(a, a)] -> [a]
flatten = foldr (\(x, y) tl -> x : y : tl) []
(Note that flatten = map fst is insufficient, since x == y || x == z in the questioner's program implies that either the first or second element can be matched against.)
Next, for each string in the first list, we check whether it is present in the second list:
allPresent :: Eq a => [a] -> [a] -> Bool
allPresent xs ys = all (`elem` ys) xs
Then func is simply the composition of these:
func :: Eq a => [a] -> [(a, a)] -> Bool
func xs ys = allPresent xs (flatten ys)
What's wrong with your implementation? First, your first two clauses are overly specific. func [] ys is True regardless of ys, so there's no need to specify that ys is non-empty. Second, the third clause drops the first pair when recursing, so something like func ["Jeff", "Thomas"] [("Thomas", "22"), ("Jeff", "16")] would be erroneously false. A correct implementation in this style would be
func :: forall a. Eq a => [a] -> [(a, a)] -> Bool
func [] _ = True
func (x:xs) ys = go x ys && func xs ys
where
go :: a -> [(a, a)] -> Bool
go _ [] = False
go x ((y1, y2):ys)
| x == y1 || x == y2 = True
| otherwise = go x ys
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.
I'm having trouble with one of my hw problems.
Write a recursive function that constructs a set
mkSet :: Eq a => [a] −> Set a
One of the hints given is I should be using another function called isElement to check each value for duplicates. Here is what I have for isElement
isElement :: Eq a => a -> [a] -> Bool
isElement x [] = False
isElement x (y:xs) = if x == y then True else isElement x xs
One of the main errors I tend to get is everytime I call isElement, the value from mkSet returns as a Bool (which I am not sure how I am doing).
This is what I have for my mkSet currently (also keep in mind I'm just starting to learn Haskell)
mkSet :: Eq a => [a] -> Set a
mkSet x [] = isElement x (xs)
What is it that I should be doing?
Thanks!
First of all, I think you ment mkSet (x:xs) instead of mkSet x [], because you use the xs.
Your function 'mkSet x [] = isElement x (xs)' is calling the function isElement, which in his place returns a Bool. So what you are assigning to nkSet x [] is a Bool and no a Set a.
so what you do want is something like this:
mkSet' :: [a] -> [a]
mkSet' [] = []
mkSet' (x:[]) = [x]
mkSet' (x:xs) = if (isElement x xs) then (mkSet' xs) else (x:(mkSet' xs))
This function gives you a list with unique elements. The only thing you have to do know is to turn it into a set.
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.
So I'm following the tutorial Learn you a Haskell for Great Good! and so far I absolutely love Haskell. But in one of the functions mentioned in the tutorial I'm getting a warning that the if-statement is redundant.
Edit: Let me be clear, the intent of the function is to act exactly the same way the elem function works (the one that is provided with Haskell by default).
Here's the original function:
elem' :: (Eq a) => a -> [a] -> Bool
elem' y ys = foldl (\acc x -> if x == y then True else acc) False ys
Originally there were two warnings, one was eta reduction, so I removed the ys from the beginning and end of the function name to arrive at:
elem' :: (Eq a) => a -> [a] -> Bool
elem' y = foldl (\acc x -> if x == y then True else acc) False
Now I tried to reduce the function to the following and it results in an error:
elem' :: (Eq a) => a -> [a] -> Bool
elem' y = foldl (\acc x -> x == y)
I think I'm just very new to Haskell and can't see the obvious solution. Can someone tell me what code change would keep the function working correctly and yet remove the compiler warning?
if x == y then True else acc is the same as x == y || acc.
Typing your last definition into GHCi without a type annotation:
Prelude> let elem' y = foldl (\acc x -> x == y)
Prelude> :t elem'
elem' :: (Eq b) => b -> Bool -> [b] -> Bool
It doesn't match your declared type.
You forgot the False at the end! If you add it in:
Prelude> let elem' y = foldl (\acc x -> x == y) False -- note the False at the end
Prelude> :t elem'
elem' :: (Eq b) => b -> [b] -> Bool
It has the right type!