Using few functions in Haskell together - haskell

I made this code where I need to find elements in a list that appears only once
for example: for input [1,2,2,3,4,4], the output will be: [1,3]
unique :: =[a]->[a]
unique xs =[x|x<-xs, elemNum x xs ==1]
elemNum :: Int -> [Int]->[Int]
elemNum x (y:ys)
| x==y =1+ elemNum x ys
| otherwise =elemNum x ys
However I am getting an error :
Not in scope: `unique'
Is this the correct way to use 2 function in Haskell? (define them at the same file), What'a wrong with the code?

There are a few problems in your code:
type signature of unique is wrong, it should be
unique :: (Eq a) => [a] -> [a]
that type constraint (Eq a) comes from elemNum
type signature of elemNum also wrong, it should be
elemNum :: (Eq a) => a -> [a] -> Int
that type constraint comes from ==, and the type of its first parameter no need to be Int, but its return type should be Int because you want to find out how many x in xs.
Also, you forgot to deal with empty list in that definition.
Here is a fixed version of your code:
unique :: (Eq a) => [a] -> [a]
unique xs =[x| x<-xs, elemNum x xs == 1]
elemNum :: (Eq a) => a -> [a] -> Int
elemNum x [] = 0
elemNum x (y:ys)
| x==y = 1 + elemNum x ys
| otherwise = elemNum x ys
Here is another implementation:
onlyOnce [] = []
onlyOnce (x:xs)
| x `elem` xs = onlyOnce $ filter (/=x) xs
| otherwise = x : onlyOnce xs
If x occurs in xs, then the result of onlyOnce (x:xs) should be the same as the result of applying onlyOnce to the result of removing all occurrences of x from xs; otherwise, x occurs in (x:xs) only once, so x should be part of the final result.

You have an equals sign in the Type declaration for unique:
unique :: =[a]->[a]
should be
unique :: [a] -> [a]

In my opinion it is much easier to implement this function using functions from Data.List module:
import Data.List
unique :: (Ord a) => [a] -> [a]
unique = map (\(y,_) -> y) . filter (\(x,l) -> l == 1) . map (\l#(x:xs) -> (x,length l)) . group . sort

Related

Get duplicated elements in a list without using (Ord a)

I have been trying to make a function that concatenates a list of lists, sorts it, and gives back the duplicated values.
The issue I'm facing is that it tells me to change (Eq a) to (Ord a) for the last function, but I cannot do this. How can I solve this without changing (Eq a) to (Ord a) ?
This is the code I have:
group :: Eq a => [a] -> [[a]]
group = groupBy (==)
groupBy :: (a -> a -> Bool) -> [a] -> [[a]]
groupBy _ [] = []
groupBy eq (x:xs) = (x:ys) : groupBy eq zs
where (ys,zs) = span (eq x) xs
uniq :: Eq b => [b] -> [b]
uniq = map head . group
insert :: Ord a => a -> [a] -> [a]
insert x [] = [x]
insert x (y:ys) | x < y = x:y:ys
| otherwise = y:(insert x ys)
isort :: (Eq a, Ord a) => [a] -> [a]
isort [] = []
isort (x:xs) = insert x (isort xs)
kms :: Ord a => [a]
kms xss = uniq (isort (concat xss))
pairwiseIntersections :: (Eq a) => [[a]] -> [a]
pairwiseIntersections xss = kms xss
You cannot sort a list without its elements having some ordering -- meaning that they must be instances of Ord.
You can do other things to deduplicate a list, like nub, but if you want it sorted you need Ord or an equivalent ordering.
You mention no complexity requirements, so the simplest approach could be
keepOnlyDups [] = []
keepOnlyDups (x:xs) = [x | elem x xs] ++ keepOnlyDups [ y | y <- xs, y /= x]
removeExtras [] = []
removeExtras (x:xs) = [x] ++ removeExtras [ y | y <- xs, y /= x]
answering both your question's text and the implied meaning of the code.
Implementing keepOnlyUniques is left as an exercise, if you're interested in that.

How to pattern match the end of a list?

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?

How to extract the same elements from two lists in Haskell?

here's my question:
How to extract the same elements from two equal length lists to another list?
For example: given two lists [2,4,6,3,2,1,3,5] and [7,3,3,2,8,8,9,1] the answer should be [1,2,3,3]. Note that the order is immaterial. I'm actually using the length of the return list.
I tried this:
sameElem as bs = length (nub (intersect as bs))
but the problem is nub removes all the duplications. The result of using my function to the former example is 3 the length of [1,3,2] instead of 4 the length of [1,3,3,2]. Is there a solution? Thank you.
Since the position seems to be irrelevant, you can simply sort the lists beforehand and then traverse both lists:
import Data.List (sort)
intersectSorted :: Ord a => [a] -> [a] -> [a]
intersectSorted (x:xs) (y:ys)
| x == y = x : intersectSorted xs ys
| x < y = intersectSorted xs (y:ys)
| x > y = intersectSorted (x:xs) ys
intersectSorted _ _ = []
intersect :: Ord a => [a] -> [a] -> [a]
intersect xs ys = intersectSorted (sort xs) (sort ys)
Note that it's also possible to achieve this with a Map:
import Data.Map.Strict (fromListWith, assocs, intersectionWith, Map)
type Counter a = Map a Int
toCounter :: Ord a => [a] -> Counter a
toCounter = fromListWith (+) . flip zip (repeat 1)
intersectCounter :: Ord a => Counter a -> Counter a -> Counter a
intersectCounter = intersectionWith min
toList :: Counter a -> [a]
toList = concatMap (\(k,c) -> replicate c k) . assocs
intersect :: Ord a => [a] -> [a] -> [a]
intersect xs ys = toList $ intersectCounter (toCounter xs) (toCounter ys)
You could write a function for this. There is probably a more elegant version of this involving lambda's or folds, but this does work for your example:
import Data.List
same (x:xs) ys = if x `elem` ys
then x:same xs (delete x ys)
else same xs ys
same [] _ = []
same _ [] = []
The delete x ys in the then-clause is important, without that delete command items from the first list that occur at least once will be counted every time they're encountered.
Note that the output is not sorted, since you were only interested in the length of the resulting list.
import Data.List (delete)
mutuals :: Eq a => [a] -> [a] -> [a]
mutuals [] _ = []
mutuals (x : xs) ys | x `elem` ys = x : mutuals xs (delete x ys)
| otherwise = mutuals xs ys
gives
mutuals [2,4,6,3,2,1,3,5] [7,3,3,2,8,8,9,1] == [2,3,1,3]

elemIndices in Haskell

I wrote the code to get the element index
elemIndex :: [String] -> [String] -> [Int]
elemIndex [] [] = []
elemIndex x y = elemIndex True [(elem a y) | a <- x ]
is there any alternative way/similer of performing the above logic?
and also i've seen that some use
index [] _ = []
to return null lists
could you pls explain the use of underscore?
//edit 1
it is suposed to return the index of the values in the list.
eg: elemIndex ["asde","zxc","qwe"] ["qwe","zxc"]
returns [1,2] as the answer
thanks
elemIndex takes two arguments (two lists). Right now you recursively call it with an additional argument of type bool (namely True). That will not work. What you probably want to do, is create a helper function, as I showed you an hour ago.
The _, as used as a formal argument, matches any input. It does not have a name, and as such, you cannot use that which is matched.
Aside from that, you probably don't want to use booleans, but integers (to keep track of a counter). The elem function only tells you whether some value is part of a list, not where it is. So, it is of little use to you. Since this appears to be homework I will not provide a solution to your problem, but perhaps you should split your code in two:
indices :: (Eq t) => [t] -> [t] -> [Integer]
getIndex :: (Eq t) => [t] -> t -> Integer
(getIndex may use a helper function getIndex' :: (Eq t) => [t] -> t -> Integer -> Integer.)
Edit: One possible solution (which uses a hack, it's nicer to use the Maybe monad):
indices :: (Eq t) => [t] -> [t] -> [Integer]
indices xs ys = filter (>= 0) $ map (getIndex xs) ys
getIndex :: (Eq t) => [t] -> t -> Integer
getIndex xs y = getIndex' xs y 0
where
getIndex' :: (Eq t) => [t] -> t -> Integer -> Integer
getIndex' [] _ _ = -1
getIndex' (x:xs) y i | x == y = i
| otherwise = getIndex' xs y (i + 1)
A version with the Maybe monad:
import Data.Maybe
indices :: (Eq t) => [t] -> [t] -> [Integer]
indices xs ys = mapMaybe (getIndex xs) ys
getIndex :: (Eq t) => [t] -> t -> Maybe Integer
getIndex xs y = getIndex' xs y 0
where
getIndex' :: (Eq t) => [t] -> t -> Integer -> Maybe Integer
getIndex' [] _ _ = Nothing
getIndex' (x:xs) y i | x == y = Just i
| otherwise = getIndex' xs y (i + 1)
And a version that leaves all heavy lifting to the standard library:
import Data.List
import Data.Maybe
indices :: (Eq t) => [t] -> [t] -> [Int]
indices xs ys = mapMaybe (`elemIndex` xs) ys
index [] _ = []
is the same as
index [] x = []
except you cannot use the _ on the right hand side of the equals sign.
I don't understand what you want elemIndex to do.
I'd implement your function this way:
elemIndices acc n [] _ = acc
elemIndices acc n _ [] = acc
elemIndices acc n (x:x') (y:y') = if x == y then
elemIndices (n:acc) (n+1) x' y'
else
elemIndices acc (n+1) x' (y:y')
elemIndex x y = reverse $ elemIndices [] 1 x y
When the elements in your source list are in the same order as the elements you look for, this is much more efficient (no use of elem - tail recursion). Ex:
elemIndex [3..7] [4, 6] -- Yields [2, 4]

Haskell "Couldn't match expected type ‘a’ with actual type ‘[a0]’"

Im doing a project in Haskell where I am trying to create a function which takes two list inputs and then returns a union of the list but without any duplicates.
The problem is that I keep getting the error message:
Couldn't match expected type ‘a’ with actual type ‘[t0]’
‘a’ is a rigid type variable bound by
the type signature for newList :: [a] -> [a] -> [a]
Here is my code:
allList :: (Eq a) => [a] -> [a] -> [a]
allList [] [] = []
allList x y = (x ++ y)
checkDup [] = []
checkDup (z:zs)
| z `elem` zs = checkDup zs
| otherwise = z : checkDup zs
newList :: (Eq a) => [a] -> [a] -> [a]
newList [] [] = []
newList x y = [checkDup z | z <- allList x y]
The first allList function creates a list of the two list, the checkDup creates a new list without any duplicates and the newList uses list comprehension to pass the combined list to the checkDup.
Anyone know where I am going wrong?
The problem lies here:
newList x y = [checkDup z | z <- allList x y]
z is supposed to be a list you pass to checkDup, but in this case, z is just a single element
Maybe you want:
newList x y = checkDup $ allList x y
newList can be declared as follows:
newList :: (Eq a) => [a] -> [a] -> [a]
newList = checkDup . allList
Since #Smac89 answered your question, why not use a data representation like Data.Set?
import qualified Data.Set as S
allList :: Ord a => [a] -> [a] -> [a]
allList xs ys = S.toList $ S.union (S.fromList xs) (S.fromList ys)
(although the continued use of Sets is probably even more meaningful.)
Or by using Data.List:
import Data.List
newList :: Eq a => [a] -> [a] -> [a]
newList xs ys = nub $ xs ++ ys

Resources