Related
I'm trying to test lists for duplicates but when I compile and enter
repeated [1,2,3,4]
it outputs True. What's wrong?
belongs :: Eq a => a -> [a] -> Bool
belongs n [] = False
belongs n (x:xs) | n == x = True
| otherwise = belongs n xs
repeated :: [Integer] -> Bool
repeated [] = False
repeated (x:xs) | belongs x xs = True
| otherwise = belongs (head xs) xs
"belongs (head xs) xs" checks whether xs's head is within xs, which will always be true.
(Except when xs is empty, in which case your program will crash! "head" is a partial function, crashes with empty lists)
This would fix it (as pointed by #talex too, but I also suggest making it more general, there is no need to specialize it to Integer):
repeated :: Eq a => [a] -> Bool
repeated [] = False
repeated (x:xs) | belongs x xs = True
| otherwise = repeated xs
You want
repeated :: [Integer] -> Bool
repeated [] = False
repeated (x:xs) | belongs x xs = True
| otherwise = repeated xs
So, I am trying to implement a function that, given a list of 3 elements ((Int,Int),Int), returns True when on the second position is the same value for all 3 and False otherwise.
For instance, [((1,2),7),((5,3),7),((1,9),7)] should return True and [((1,2),3),((5,3),3),((1,9),5)] should return False.
Here is my code:
bc :: [((Int,Int),Int)]
wcheck :: [((Int,Int),Int)] -> Bool
wcheck bc
| (( fst(fst bc) == fst(snd bc) ) && ( fst(snd bc) == fst(last bc) )) = True
| otherwise = False
And the error that I get:
E:\\study related\Module1\week 4\ttt.hs:55:65: error:
* Couldn't match expected type `[(a, b0)]'
with actual type `((a, b), (a, b1))'
* In the first argument of `last', namely `bc'
In the first argument of `fst', namely `(last bc)'
In the second argument of `(==)', namely `fst (last bc)'
* Relevant bindings include
bc :: ((a, b), (a, b1))
(bound at E:\\study related\Module1\week 4\ttt.hs:54:8)
wcheck :: ((a, b), (a, b1)) -> Bool
(bound at E:\\study related\Module1\week 4\ttt.hs:54:1)
|
55 | | (( fst(fst bc) == fst(snd bc) ) && ( fst(snd bc) == fst(last bc) )) = True
|
Could you please tell me why I get this error and a way to fix it? Thank you.
It will probably be easier if we perform simple pattern matching instead of using fst :: (a, b) -> a, etc.
Second item of the first item of the tuple
We can use a pattern ((_, x), _) to obtain the second element from such 2-tuple wrapped in a 2-tuple.
So we can use pattern matching like:
wcheck :: [((Int,Int),Int)] -> Bool
wcheck [((_, x), _), ((_, y), _), ((_, z), _)] = x == y && y == z
wcheck _ = False
So here if the list contains three elements, we unpack the elements, and then check if the "second item"s are equal to each other. In case the pattern does not match (for a list with too few, or too much elements), we just return False.
But a "list of three elements" does not make much sense. In case the number of elements is known at compile time, it is better to use a tuple, since in that way, the compiler can verify that you can only provide 3-tuples to that function.
Second item of the tuple
In case we are interested in the second item of the tuple, we can use (_, x) as pattern (we are not interested in the first item whatsoever):
wcheck :: [((Int,Int),Int)] -> Bool
wcheck [(_, x), (_, y), (_, z)] = x == y && y == z
wcheck _ = False
Note that we can generalize the signature with:
wcheck :: Eq c => [((a, b), c)] -> Bool
wcheck [(_, x), (_, y), (_, z)] = x == y && y == z
wcheck _ = False
fst and snd are not very nice in this situation. We can extract the bit we care about by doing a pattern match:
let (_,y) = x in ...
Now you want to do that to each element of your list (to check that every element has the same second value):
map (\(_,x) -> x)
And then you want to check that they are all equal:
allEqual :: Eq a => [a] -> Bool
allEqual [] = True
allEqual (x:xs) = all (\y->x==y) xs
This gets the first element, x, from a list (if it exists) and checks that ever other item y satisfies the test that x==y
So we can now write your function:
wcheck xs = allEqual (map (\(_,y) -> y) xs)
Given that you want to test the equality of the second element of the outer pair, there are so many ways to do this, including the following.
First, fmapping snd gives you these elements:
λ> fmap snd [((1,2),7),((5,3),7),((1,9),7)]
[7,7,7]
Now you can group them to lists of consecutive equal numbers:
λ> import Data.List
λ> (group . fmap snd) [((1,2),7),((5,3),7),((1,9),7)]
[[7,7,7]]
The values are equal if the length of this list of lists is at most one (assuming an empty list of such pairs is defined to have equal second elements):
λ> (length . group . fmap snd) [((1,2),7),((5,3),7),((1,9),7)]
1
Putting these together we can define
import Data.List
equalSnds :: Eq a => [(b, a)] -> Bool
equalSnds xs = (length . group . fmap snd) xs <= 1
So that
λ> equalSnds [((1,2),7),((5,3),7),((1,9),7)]
True
λ> equalSnds [((1,2),3),((5,3),3),((1,9),5)]
False
If you want to also test for the length of the list, you can do it separately:
wcheck :: [((Int,Int),Int)] -> Bool
wcheck xs = length xs == 3 && equalSnds xs
im learning functional programming with Haskell and i have this exercise where i have something like [a], z, with [a] any kind of list and z the element that im gonna erase inside [a]. This problem it's kinda easy to solve (even for a newbie like me in Haskell) but I am having troubles with the way I need to print the output.
I need to create a tuple where the first element is the list without any z element and the number of times that it found z inside of a. Couple examples:
Input: [2,3,4,2,2] 2
Output: ([3,4],3)
Input: [1,1,1,1] 1
Output: ([],4)
Input: [1,2,3,4] 5
Output: ([1,2,3,4],0)
So far i've done something like this but I don't know how to keep going:
ex3 :: (Eq a, Num a) => [a] -> a -> ([a],Int)
ex3 [] _ = ([],0)
ex3 (x:xs) z | x == z = (xs,1) -- this line is wrong, but idk how to fix it
| otherwise = ([0],0) -- same here
I've done both problems individually (deleting z elements and counting how many times z is in [a]. Looks like this:
a) Deleting z elements:
ex3a :: (Eq a) => [a] -> a -> [a]
ex3a [] _ = []
ex3a (x:xs) z | x == z = ex3a xs z
| otherwise = x : ex3a xs z
b) Counting how many times z is in [a]:
ex3b :: (Eq a) => [a] -> a -> Int
ex3b [] _ = 0
ex3b (x:xs) z | x == z = 1 + ex3b xs z
| otherwise = ex3b xs z
Usually it helps to think of functions like in mathematics you think about inductive definitions. For example the first line of your function can read like:
"The ex3 of an empty list, and any element is a tuple containing the empty list and zero"
ex3 [] _ = ([], 0)
For non-empty lists of course the problem is a bit harder. Like in your code, there are basically two cases here.
"The ex3 of a non-empty list and an element z where the head of the list is not equal to z is the same as the ex3 of the tail of the list, but prepended with the head of that list", so we can write it like:
ex3 [] _ = ([], 0)
ex3 (x:xs) z | x /= z = (x:t, n)
| otherwise = ...
where (t, n) = ex3 xs z
So here we make a recursive call to ex3 with the tail of the list xs, and we obtain the result tuple (t, n), so t contains the "erased" tail, and n the number of times we removed the element, and in case x /= z, then we can return (x:t, n), since the number of removals does not change, but we have to prepend x to the list.
"The ex3 of a non-empty list and an element z where the head of the list is equal to z is the same as the ex3 of the tail of the list but with an incremented count", so:
ex3 :: (Eq a, Num n) => [a] -> a -> ([a], n)
ex3 [] _ = ([], 0)
ex3 (x:xs) z | x /= z = (x:t, n)
| otherwise = (t, n+1)
where (t, n) = ex3 xs z
We then obtain the expected results:
Prelude> ex3 [2,3,4,2,2] 2
([3,4],3)
Prelude> ex3 [1,1,1,1] 1
([],4)
Prelude> ex3 [1,2,3,4] 5
([1,2,3,4],0)
Just for fun, this is how I would implement that function:
import Data.Foldable
import Data.Monoid
ex3 :: Eq a => [a] -> a -> ([a], Int)
ex3 haystack needle = getSum <$> foldMap inject haystack where
inject hay | hay == needle = ([], 1)
| otherwise = ([hay], 0)
What I like about this is that the recursion pattern is immediately obvious -- at least to those familiar with Haskell's standard library -- without careful scrutiny (because it is just a call to foldMap).
The partition function consumes a predicate and a list; it produces a pair of lists whose first element satisfies the predicate, the second doesn't.
import Data.List (partition)
ex4 :: Eq a => [a] -> a -> ([a], Int)
ex4 xs x = length <$> partition (/= x) xs
I try to learn how many elements are the same in the given two sets. To be clear,
let a = ["t","k","m"]
let b = ["k","b","t","c"]
"t" and "k" are parts of both lists, so the return will be 2. How can I implement like this function without using any library and using recursion?
You can use the module Data.Set to convert the two lists to sets and calculate the size of the intersection:
let a = Set.fromList ["t","k","m"]
let b = Set.fromList ["k","b","t","c"]
print $ Set.size (a `Set.intersection` b)
Live demo
As a general rule, if the order of the elements in the list doesn't matter and the list doesn't contain duplicates it's a good idea to convert it into a Set.
For some reason you don't want to use the standard library. If you don't care about algorithmic complexity you can then use:
length $ Prelude.filter (`elem` b) a
Live demo
of if you want it to be put into recursive form, then it's something like this:
countDuplicates :: (Eq a) => [a] -> [a] -> Int
countDuplicates [] b = 0
countDuplicates (x:rest) b =
let index = if x `elem` b then 1 else 0
in index + countDuplicates rest b
Live demo
which if you don't want to use elem either will be further expanded to:
countDuplicates :: (Eq a) => [a] -> [a] -> Int
countDuplicates [] b = 0
countDuplicates (x:rest) b =
let myElem a [] = False
myElem a (al:lst) = if a == al then True else myElem a lst
index = if x `myElem` b then 1 else 0
in index + countDuplicates rest b
Live demo
Without using any extra functions you can write it simply as follows
countIntersect :: (Eq a) => [a] -> [a] -> Int
countIntersect _ [] = 0
countIntersect [] _ = 0
countIntersect (x:xs) y'#(y:ys) | x==y = 1 + countIntersect xs ys
| otherwise = countIntersect [x] ys + countIntersect xs y'
essentially, the way you would do by hand, compare the first two elements if same increase the counter and move the next element in both list. If not equal compare the first element of the first list with the rest of second list and remainder of the first list to the second list.
I have code like this:
appd (a:e) ((c,b):bs) | a == c && bs /= [] = b:appd(a:e) bs
| a /= c && bs /= [] = appd (a:e) bs
| a /= c && bs == [] = appd e ((c,b):bs)
| otherwise = b:appd e ((c,b):bs)
It loops throught two lists like [1,2,3] and [(1,2),(6,5),(3,5)] and takes first element of first list and compares it to first element of each tuple in other list, if they are equal then save second element of this tuple. It works fine, but comparison does not work if I take second element of first list, in this case 2.
For example if I have lists like [1,2,3] and [(1,2),(6,5),(3,5)], then function takes 1 from first list and compares to 1, then to 6, then to 3, that works but it does not take second element of first list - 2 and does not do the comparison again. Whats wrong?
First of all, let me note that you should have included the error message you were getting. You should also have shown us some sample output and sample input.
Anyway: your current appd doesn't handle empty lists, so you need to start by adding cases for that:
appd _ [] = []
appd [] bs = snd <$> bs -- you can decide to use [] instead
appd (a:e) ((c,b):bs)
| a == c && bs /= [] = b:appd(a:e) bs
| a /= c && bs /= [] = appd (a:e) bs
| a /= c && bs == [] = appd e ((c,b):bs)
| otherwise = b:appd e ((c,b):bs)
now your function works on the input you've provided, but I'm not sure it returns the results you desire:
*Main> appd [1,2,3] [(1,2),(6,5),(3,5)]
[2,5,5]
Furthermore, I've cleaned up your code a little bit and annotated your function with an explicit type signature:
appd :: (Eq a, Eq b) => [a] -> [(a,b)] -> [b]
appd [] bs = snd <$> bs
appd _ [] = []
appd as#(a:ass) bs#((c,b):bss)
| a == c && bss /= [] = b : appd as bss
| a /= c && bss /= [] = appd as bss
| a /= c && bss == [] = appd ass bs
| otherwise = b : appd ass bs
Also, you can use a much simpler, non-recursive implementation to get the same results as above:
appd :: (Eq a, Eq b) => [a] -> [(a,b)] -> [b]
appd as bs = snd <$> filter (\(a,_) -> a `elem` as) bs
or if you like point free (a.k.a. tacit):
appd :: (Eq a, Eq b) => [a] -> [(a,b)] -> [b]
appd as = (snd <$>) . filter ((`elem` as) . fst)
Note: <$> is an alias for fmap, which in turn behaves exactly like map when used on lists.