Make Haskell List Recursion function more efficient - list

I've written a function that will compare two lists and check to see if the first is a prefix of the second and it must be done using recursion.
For example:
prefix [1,2] [1,2,3]
>True
prefix [2,1,4] [2,1,13,4]
>False
Now I've done this but I feel it's inefficient:
prefix :: [Int] -> [Int] -> Bool
prefix (x:xs) (y:ys)
| null xs = True
| x == y && head xs == head ys = True && prefix xs ys
| head xs /= head ys = False
I was hoping it could be done more efficiently and with some better pattern matching. Can it be?

You don't need to use the head function at all. That doubles the number of comparisons. Try this:
prefix :: [Int] -> [Int] -> Bool
prefix [] _ = True
prefix _ [] = False
prefix (x:xs) (y:ys)
| x == y = prefix xs ys
| otherwise = False

Chad Gilbert's solution can be streamlined very slightly:
prefix :: [Int] -> [Int] -> Bool
prefix [] _ = True
prefix (x:xs) (y:ys)
| x == y = prefix xs ys
prefix _ _ = False
This won't affect the performance, but it demonstrates a language feature: when all the guards on a pattern fail, that match will be abandoned and matching will resume with the next pattern.

Prelude > let prefix [] _ = True
Prelude | prefix _ [] = False
Prelude | prefix (x:xs) (y:ys) = if ( x==y) then prefix xs ys else False
Examples:
Prelude> prefix [1,3] []
False
Prelude> prefix [] [1,2,3]
True
Prelude> prefix [1,2] [1,2,3]
True

Related

Haskell how to drop all 0 of the list until one of the elements /= 0?

I'm new to Haskell and I'm trying to figure out how to write a code, that drops all zeros until an element of the list is >0.
So for example:
Input: [0,0,5,6,0]
Output: [5,6,0]
So far I have wrote this:
zeroUntil :: [Int] -> [Int]
zeroUntil [] = []
zeroUntil (x:xs)
| x == 0 = drop x (xs)
| otherwise = zeroUntil xs
But somehow intead of [5,6,0] i get [ ].
Can anybode please explain what did I do wrong?
You can make use of dropWhile :: (a -> Bool) -> [a] -> [a] and thus drop items as long as these are zeros:
zeroUntil :: [Int] -> [Int]
zeroUntil = dropWhile (0 ==)
If you want to drop zeros until an element is greater than zero, you can make use of recursion. Here your recursive case should yield elements if these are less than zero:
zeroUntil :: [Int] -> [Int]
zeroUntil [] = []
zeroUntil (0:xs) = zeroUntil xs
zeroUntil (x:xs)
| x > 0 = x : xs -- ← end of recursion, return the list
| otherwise = x : zeroUntil xs -- ← yield x and recurse
for example:
Prelude> zeroUntil [0,0,5,6,0]
[5,6,0]
Prelude> zeroUntil [0,-1,5,6,0]
[-1,5,6,0]
zeroUntil :: [Int] -> [Int]
zeroUntil [] = []
zeroUntil (x:xs)
| x == 0 = drop x (xs)
| otherwise = [x] ++ (zeroUntil xs)
You have to add the first element (x) to the list returned by the recursive call, otherwise you return a empty list.

Determining if there are repeated elements in a list in Haskell

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

Haskell: Check if the first list is a prefix of the second

I am trying to write a program that checks if the first list is a prefix of the second list. for example, [5,6] is prefix of [1,5,6,7]. here is my working code but basically I don't have an idea on how to do it.
prefix [Int] -> [Int] -> Bool
prefix [] [] = []
prefix y (x:xs)
| x == y = prefix y xs
| otherwise = 0
any help please ?
Your code does not make much sense if we look at the types:
prefix [Int] -> [Int] -> Bool
prefix [] [] = []
prefix y (x:xs)
| x == y = prefix y xs
| otherwise = 0
Since the two arguments are lists ([Int]), this thus means that y is an [Int], x is an Int, and xs is an [Int]. But then you compare x == y, you can not compare a list with an element. (==) is defined as (==) :: Eq a => a -> a -> Bool.
There are also other problems here: you return a list in the first clause, but the return type is a Bool, and later you return a 0 (again, it should be a Bool).
In case we define a function, we first need to define a certain model for it. When is a list l1 a prefix of a list l2? In case l1 is an empty list, then l1 is always a prefix, regardless of the value of the second list, so:
prefix [] _ = True
In case l1 is a list (i.e. (x:xs)), then it is not a prefix in two cases: (1) in case l2 is an empty list; and (2) in case the first item of l2 (y in (y:ys)) is not equal to x, so:
prefix _ [] = False
prefix (x:xs) (y:ys) | x /= y = False
| otherwise = ...
Now the question is what to do with prefix (x:xs) (y:ys) in case x == y. In that case we recurse on the two list, so the result of prefix (x:xs) (y:ys) == prefix xs ys (only in case x == y), so:
| otherwise = prefix xs ys
Or now in full:
prefix :: [Int] -> [Int] -> Bool
prefix [] _ = True
prefix _ [] = False
prefix (x:xs) (y:ys) | x /= y = False
| otherwise = prefix xs ys
We can further generalize the expression to Eq a => [a] -> [a] -> Bool such that it works with any type a that is an Eq instance (so there is a (==) instance defined over a):
prefix :: Eq a => [a] -> [a] -> Bool
prefix [] _ = True
prefix _ [] = False
prefix (x:xs) (y:ys) | x /= y = False
| otherwise = prefix xs ys
We can also swap the conditions, since usually positive logic is easier to understand than negative logic:
prefix :: Eq a => [a] -> [a] -> Bool
prefix [] _ = True
prefix _ [] = False
prefix (x:xs) (y:ys) | x == y = prefix xs ys
| otherwise = False
now we can furthermore remove the guards, and use an (&&) :: Bool -> Bool -> Bool instead:
prefix :: Eq a => [a] -> [a] -> Bool
prefix [] _ = True
prefix _ [] = False
prefix (x:xs) (y:ys) = x == y && prefix xs ys
Just leaving my two cents here with a combination of functions from Prelude:
isPrefix :: Eq a => [a] -> [a] -> Bool
isPrefix l1 l2 = take (length l1) l2 == l1

Largest prefix list of lists

I need to define a function largestPrefix that goes through a list of strings
and returns the longest prefix of two adjacent strings of the list in a tuple. The first element of the tuple is the length of the prefix .
a.e.: largestPrefix ["a","abca","bca","bcadabca","ca","cdabca"] => (3,"bca")
I have already built a function for two Stings, but have no idea how to use that on a list of lists. To ensure the adjacency I thought about using this:
prefix:: String -> String -> String
prefix (x:xs) (y:ys) | x:xs == "" = ""
| y:ys == "" = ""
| x == y = x:prefix xs ys
| otherwise = ""
So I cleaned up your function a bit and added the following idea:
if you write a function that applies an operator to every two consecutive pairs of a list (pairwise) then you should be able to finish your work:
pairwise :: (a -> a -> b) -> [a] -> [b]
pairwise f (x:xs#(y:_)) = f x y : pairwise f xs
pairwise _ _ = []
prefix:: String -> String -> String
prefix (x:xs) (y:ys)
| x == y = x:prefix xs ys
| otherwise = ""
prefix _ _ = ""
here is an example:
λ> pairwise prefix ["a","abca","bca","bcadabca","ca","cdabca"]
["a","","bca","","c"]
so maybe someone was unhappy because I did not resolve everything so here you go:
largestPrefix :: [String] -> (Int, String)
largestPrefix xs = maximumBy (compare `on` length . snd) $ zip [1..] (pairwise prefix xs)
where you have to import this to work:
import Data.List (maximumBy)
import Data.Function (on)
example
λ> largestPrefix ["a","abca","bca","bcadabca","ca","cdabca"]
(3,"bca")

Comparing lists in Haskel

I have to define a function called zeros which takes input of two lists and returns a boolean which returns True if the number 0 appears the same amount of times in each list and false otherwise.
This is the last question in my homework and and I have managed to solve the question get it to work but I wondered if anybody can spot ways in which to reduce the amount of code, any ideas are appreciated. My code so far is as follows:
x :: Int
x = 0
instances::[Int]->Int
instances [] = 0
instances (y:ys)
| x==y = 1+(instances ys)
| otherwise = instances ys
zeros :: [Int] -> [Int] -> Bool
zeros [] [] = False
zeros x y
| ((instances x) == (instances y)) = True
| otherwise = False
Without giving too much away, since this is homework, here are a few hints.
Do you know about list comprehensions yet? They would be useful in this case. For example, you could combine them with an if expression to do something like this:
*Main> let starS s = [if c == 's' then '*' else ' ' | c <- s]
*Main> starS "schooners"
"* *"
You can even use them to do filtering. For example:
*Main> let findFives xs = [x | x <- xs, x == 5]
*Main> findFives [3,7,5,6,3,4,5,7,5,5]
[5,5,5,5]
Neither of these is a complete answer, but it shouldn't be hard to see how to adapt these structures to your situation.
You should also think about whether you actually need a guard here! For example, here's a function written with a guard in the same style as yours:
lensMatch [] [] = True
lensMatch xs ys
| ((length xs) == (length ys)) = True
| otherwise = False
Here's a function that does the same thing!
lensMatch' xs ys = length xs == length ys
You can see that they are the same; testing the first:
*Main> lensMatch [1..4] [1..4]
True
*Main> lensMatch [1..4] [1..5]
False
*Main> lensMatch [] [1..5]
False
*Main> lensMatch [] []
True
And testing the second:
*Main> lensMatch' [1..4] [1..4]
True
*Main> lensMatch' [1..4] [1..5]
False
*Main> lensMatch' [] [1..5]
False
*Main> lensMatch' [] []
True
Finally, I agree very strongly with sblom's comment above; zeros [] [] should be True! Think about the following statement: "For each item x in set s, x > 0". If set s is empty, then the statement is true! It's true because there are no items in s at all. This seems to me like a similar situation.
I can't believe nobody has suggested to use foldr yet. Not the shortest or best definition, but IMO the most educational:
instances :: Eq a => a -> [a] -> Int
instances n = foldr incrementIfEqual 0
where incrementIfEqual x subtotal
| x == n = subtotal + 1
| otherwise = subtotal
zeros :: Num a => [a] -> [a] -> Bool
zeros xs ys = instances 0 xs == instances 0 ys
Though for a really brief definition of instances, what I came up with is basically the same as Abizern:
instances :: Eq a => a -> [a] -> Int
instances x = length . filter (==x)
Have you thought of doing this in one pass by filtering each list to get just the zeroes and then comparing the length of the lists to see if they are equal?
zeroCompare xs ys = cZeroes xs == cZeroes ys
where
cZeroes as = length $ filter (== 0) as
Instead of length and filter, you can take the result of a predicate p, convert it to 0 or 1, and sum the result:
count p = sum . map (fromEnum.p)
--or
import Data.List
count p = foldl' (\x -> (x+).fromEnum.p) 0
In your case, p is of course (==0). Converting Bool to Int using fromEnum is a very useful trick.
Another idea would be to deal with both list simultaneously, which is a little bit lengthy, but easy to understand:
zeros xs ys = cmp xs ys == 0 where
cmp (0:xs) ys = cmp xs ys + 1
cmp xs (0:ys) = cmp xs ys - 1
cmp (_:xs) ys = cmp xs ys
cmp xs (_:ys) = cmp xs ys
cmp [] [] = 0
I would break the problem down into smaller problems involving helper functions.
This is how I would break it down:
Main function to compare two counts
Count helper function
First: You need a way to count the amount of zeroes in a list. For example, I would approach this by doing the following if searching for the number of 0 in an integer list:
count :: [Int] -> Int
count xs = foldl (\count num -> if num == 0 then (count + 1) else count) 0 xs
Second: You need a way to compare the count of two lists. Essentially, you need a function that takes two lists in as parameters, calculates the count of each list, and then returns a boolean depending on the result. For example, if each list is an int list, corresponding with my count example above:
equalZeroes :: [Int] -> [Int] -> Bool
equalZeroes x y = (count x) == (count y)
You could also define count under the where keyword inside the equalZeroes function like so:
equalZeroes :: [Int] -> [Int] -> Bool
equalZeroes x y = (count x) == (count y)
where
count :: [Int] -> Int
count xs = foldl (\count num -> if num == 0 then (count + 1) else count) 0 xs
When running this code, calling the function as so would get the desired boolean values returned:
equalZeroes [0,1,4,5,6] [1,4,5,0,0]
-> False
equalZeroes [0,1,4,5,6] [1,4,5,0]
-> True