How do i achieve [x if func(x,lst) for x in list] in haskell? - haskell

Okay so I come from a python background and am new with haskell and doing an assignment. I am done with the question itself but my logic/code looks ugly and wanted to know of ways to improve it. What I want to do is iterate over a list with that list as argument to call another function.
Assuming that I want to achieve the following in haskell.
input = [1,2,2,3,3,4,5]
output = [1,4,5] #occurs Once
so i want to go from x->y
normally how I'd do it would be
def checksOnce(input):
lst = []
for val in input:
if occursOnce(val,input):
lst.append(val)
print(lst)
How do i do that iterating in haskell? I have a function that works fine for occursOnce which takes a value and list and returns a bool just like python.
checksOnce :: [Int] -> [Int] -> [Int]
checksOnce [] lst = []
checksOnce (x:xs) lst
| occursOnce x lst = [x] ++ checksOnce xs lst
| otherwise = checksOnce xs lst
and something like mainFunc lst = checksOnce lst lst to call the above function.
The above works fine and is sufficient as far as my hw goes, but passing the same argument Once is redundant! How do i go from checksOnce :: [Int] -> [Int] -> [Int] to checksOnce :: [Int] -> [Int] and use just one list to iterate over like the above python code instead of passing the same list Once to the function?
Thanks

Haskell has list comprehensions, so you can do:
\f xs -> [x | x <- xs, f x xs]
You can also do this with a filter:
\f xs -> filter (\x -> f x xs) xs

The simplest, and probably most idiomatic, way to write this function in Haskell would be to use filter:
checksTwice :: (Eq a) => [a] -> [a] -- you can keep it as [Int] -> [Int] if you like, but this more general type signature is better because the function works on any type that can be compared for equality
checksTwice xs = filter (\x -> occursTwice x xs) xs
Or if you prefer (although the gain is debatable), rewriting the lambda in "point-free" style:
checksTwice :: (Eq a) => [a] -> [a]
checksTwice xs = filter (flip occursTwice xs) xs
(Which is exactly the answer suggested in the comments by #user2407038 - apologies for "stealing" your answer)

Well just like you did in your Python you'd want to have the variable lst only visible to the function checksTwice and not a parameter. Haskell throws some people for a loop what with it's lack of looping primitives - the solution is usually a helper function of a higher order function.
checksOnce :: [Int] -> [Int]
checksOnce xs = go xs xs
where go [] _ = []
go (x:xs) lst
| occursOnce x lst = x : go xs lst
| otherwise = go xs lst
But this pattern, including x if and only if f x is just a filter so...
checksOnce x = filter (`occursOnce` lst) xs
As #RobinZigmond noted, this still has a bug vs the behavior you desire.

Related

Apply a function to every element in a list to every element in another list - Haskell

My ultimate goal is to find if a list y contains all the elements of list x (I'm checking if x is a subset of y sort of thing)
subset x y =
and [out | z <- x
, out <- filter (==z) y ]
This doesn't work, and I know it's because z is a list still. I'm trying to make sense of this.
I think I may have to use the elem function, but I'm not sure how to split x into chars that I can compare separately through y.
I'm ashamed to say that I've been working on this simple problem for an hour and a half.
Checking whether all elements of xs are elements of ys is very straightforward. Loop through xs, and for each element, check if it is in ys:
subset xs ys = all (\x -> elem x ys) xs
You could also use the list difference function (\\). If you have list y and list x, and you want to check that all elements of x are in y, then x \\ y will return a new list with the elements of x that are not in y. If all the elements of x are in y, the returned list will be empty.
For example, if your list y is [1,2,3,4,5] and your list x is [2,4], you can do:
Prelude> [2,4] \\ [1,2,3,4,5]
[]
If list y is [1,2,3,4,5] and list x is [2,4,6], then:
Prelude> [2,4,6] \\ [1,2,3,4,5]
[6]
Easy way to reason about subsets is to use sets as the data type.
import qualified Data.Set as S
subset :: Ord a => [a] -> [a] -> Bool
subset xs ys = S.isSubsetOf (S.fromList xs) (S.fromList ys)
Then it's as simple as:
*Main> subset [1..5] [1..10]
True
*Main> subset [0..5] [1..10]
False
Let's break this down into two subproblems:
Find if a value is a member of a list;
Use the solution to #1 to test whether every value in a list is in the second one.
For the first subproblem there is a library function already:
elem :: (Eq a, Foldable t) => a -> t a -> Bool
Lists are a Foldable type, so you can use this function with lists for t and it would have the following type:
elem :: (Eq a) => a -> [a] -> Bool
EXERCISE: Write your own version of elem, specialized to work with lists (don't worry about the Foldable stuff now).
So now, to tackle #2, one first step would be this:
-- For each element of `xs`, test whether it's an element of `ys`.
-- Return a list of the results.
notYetSubset :: Eq a => [a] -> [a] -> [Bool]
notYetSubset xs ys = map (\x -> elem x ys) xs
After that, we need to go from the list of individual boolean results to just one boolean. There's a standard library function that does that as well:
-- Return true if and only if every element of the argument collection is
-- is true.
and :: Foldable t => t Bool -> Bool
EXERCISE: write your own version of and, specialized to lists:
myAnd :: [Bool] -> Bool
myAnd [] = _fillMeIn
myAnd (x:xs) = _fillMeIn
With these tools, now we can write subset:
subset :: Eq a => [a] -> [a] -> [Bool]
subset xs ys = and (map (\x -> elem x ys) xs)
Although a more experienced Haskeller would probably write it like this:
subset :: Eq a => [a] -> [a] -> [Bool]
subset xs ys = every (`elem` ys) xs
{- This:
(`elem` ys)
...is a syntactic shortcut for this:
\x -> x elem ys
-}
...where every is another standard library function that is just a shortcut for the combination of map and and:
-- Apply a boolean test to every element of the list, and
-- return `True` if and only if the test succeeds for all elements.
every :: (a -> Bool) -> [a] -> Bool
every p = and . map p

Insertion sort in Haskell

I'm doing some exercises on Haskell. First I was asked to define a function insert :: Int -> [Int] -> [Int] so that insert x xs
inserts x into the list xs in such a way that x is bigger than those
elements before it and smaller than or equal to the element that
follow it:
insert :: Int -> [Int] -> [Int]
insert x [] = [x]
insert x (y:ys) = if x < y
then x:y:ys
else y : insert x ys
Now I need to use insert to define a function insertionSort :: [Int] -> [Int]. Here's my attempt:
insertionSort :: [Int] -> [Int]
insertionSort [x] = [x]
insertionSort (x:xs) = insert x insertionSort xs
Error: Couldn't match expected type [Int] with actual type [Int] -> [Int]
Anyone know how I can fix this? Any insight is highly appreciated, thanks.
While learning some sorting algorithms myself, I'd like to give you a few suggestions/improvements to your solution:
Avoid non-exhaustive pattern matching at any case: insertionSort [] = []
Take advantage of instances of Ord over a fixed type
Consider lambda lifting by integrating insert into a where statement in order to get rid of the high-level function and save the argument x
Consider guards over if then else
Which will result in:
insertionSort :: Ord a => [a] -> [a]
insertionSort [] = []
insertionSort [x] = [x]
insertionSort (x:xs) = insert $ insertionSort xs
where insert [] = [x]
insert (y:ys)
| x < y = x : y : ys
| otherwise = y : insert ys
insert x insertionSort xs
is calling insert with three arguments (x,insertionSort,xs).
Probably you want
insert x (insertionSort xs)

How to consider previous elements when mapping over a list?

I'm stuck at making a function in Haskell wich has to do the following:
For each integer in a list check how many integers in front of it are smaller.
smallerOnes [1,2,3,5] will have the result [(1,0), (2,1), (3,2), (5,3)]
At the moment I have:
smallerOnes :: [Int] -> [(Int,Int)]
smallerOnes [] = []
smallerOnes (x:xs) =
I don't have any clue on how to tackle this problem. Recursion is probably the way of thinking here but at that point I'm losing it.
It is beneficial here not to start with a base case, but rather with a main case.
Imagine we've already processed half the list. Now we are faced with the rest of the list, say x:xs. We want to know how many integers "before it" are smaller than x; so we need to know these elements, say ys: length [y | y<-ys, y<x] will be the answer.
So you'll need to use an internal function that will maintain the prefix ys, produce the result for each x and return them in a list:
smallerOnes :: [Int] -> [(Int,Int)]
smallerOnes [] = []
smallerOnes xs = go [] xs
where
go ys (x:xs) = <result for this x> : <recursive call with updated args>
go ys [] = []
This can also be coded using some built-in higher-order functions, e.g.
scanl :: (a -> b -> a) -> a -> [b] -> [a]
which will need some post-processing (like map snd or something) or more directly with
mapAccumL :: (acc -> x -> (acc, y)) -> acc -> [x] -> (acc, [y])
mapAccumL is in Data.List.
import Data.List (inits)
smallerOnes :: [Int] -> [(Int,Int)]
smallerOnes xs = zipWith (\x ys -> (x, length $ filter (< x) ys)) xs (inits xs)

Is it possible to implement filter using foldl instead of foldr?

Is it possible to implement filter using foldl instead of foldr? If so, please explain your implementation gently.
Using difference lists:
filter' :: (a -> Bool) -> [a] -> [a]
filter' p xs = foldl (\k x -> if p x then k . (x:) else k) id xs []
Not really efficiently if you want to keep the order of the list. The naive approach is to just change it into foldl and then reverse the resulting list.
Came up with this one:
myFilter p coll =
foldl step [] coll where
step acc e
| p e = acc ++ [e]
| otherwise = acc
It's not really efficient, since it has to insert one element at the end of a list.

Foldr compare acc to empty list

I'm trying to write function and i dont know why i cannot make it in that way
ssm' = foldr (\x acc -> if acc == [] then [x]++acc else if (x > (maximum acc)) then [x]++acc else acc) []
give me a clue please.
By the way, your code looks way too complicated. You overuse if, and [x]++acc is just x:acc. Scanning acc in every step using maximum is wasteful, as its biggest element must be its head. Alltogether I'd write:
ssm' :: Ord a => [a] -> [a]
ssm' = foldr go [] where
go x [] = [x]
go x ms#(m:_)
| x > m = x:ms
| otherwise = ms
If you really like one-liners, try
import Data.List
ssm' xs = reverse $ map head $ groupBy (>) (reverse xs)
You've run into the monomorphism restriction. You can fix it by adding a type signature.
ssm' :: Ord a => [a] -> [a]
ssm' = ...

Resources