I am studying a past exam and I came across a question where I must write a function called setFunc to generate a set where I apply a function on each element in a list of tuples (which are a result of the Cartesian product operation)
First I implemented a helper function to take the union of sets:
Then I tried to implement the main function:
setFunc x y = f x y
setFunc (x:xs) (y:ys) = (f x y) OrdUnion (setFunc f xt ys)
Help on fixing setFunc would be appreciated.
I must use ordUnion somehow and I am not permitted to use sort.
This sort of constraint is expected to appear within the body of the question.
A core part of the problem is that we want the output list to be sorted (from your example), but we are told nothing about possible order-preserving properties of the argument function. So we must accept that the f x y output values will be produced in some unpredictable random order.
For example, we expect this equality to hold:
setFunc (*) [-7,2] [-7,3] == [-21,-14,6,49]
that is, the maximal output value results from the two minimal input values.
Hence, we are somewhat coerced into solving the problem in 2 steps:
produce the f x y output values in whatever order
sort the list produced in step 1.
Let's call the step 1 function cartesianFunc. It is easy to write it in recursive fashion:
cartesianFunc :: Ord c => (a -> b -> c) -> [a] -> [b] -> [c]
cartesianFunc f [] ys = []
cartesianFunc f (x:xs) ys = (map (f x) ys) ++ (cartesianFunc f xs ys)
Note that we have dropped the useless Ord constraints on types b and c.
Testing:
$ ghci
GHCi, version 8.8.4: https://www.haskell.org/ghc/ :? for help
...
λ>
λ> :load q13784671.hs
[1 of 1] Compiling Main ( q13784671.hs, interpreted )
Ok, one module loaded.
λ>
λ> cartesianFunc (*) [1,2,4] [1,3,9]
[1,3,9,2,6,18,4,12,36]
λ>
Now for step 2:
We may not use the library sort function. But we have to use function ordUnion, which merges two ordered lists into a bigger ordered list.
Assuming we had yet another function, say splitHalf, which could split a list into two roughly equal parts, we could obtain our own sort function by:
splitting the input list
recursively sorting its two halves
combining our two sorted halves using the merging ordUnion function.
To split a list, we can use the well-know tortoise-hare algorithm where at each iteration, the first part advances by one step and the second part advances by two steps.
This gives this code:
ordUnion :: (Ord a) => [a] -> [a] -> [a]
ordUnion a [] = a
ordUnion [] b = b
ordUnion (x:xs) (y:ys) = case compare x y of
LT -> x : ordUnion xs (y:ys)
EQ -> x : ordUnion xs ys
GT -> y : ordUnion (x:xs) ys
splitHalfTH :: [a] -> ([a],[a])
splitHalfTH xs = th xs xs
where
th (y:ys) (_:_:zs) = let (as,bs) = th ys zs in (y:as, bs)
th ys _ = ([],ys)
mySort :: (Ord a) => [a] -> [a]
mySort [] = []
mySort [a] = [a]
mySort xs = let (as,bs) = splitHalfTH xs in ordUnion (mySort as) (mySort bs)
and finally we can come up with our setFunc function by combining mySort and cartesianFunc:
setFunc :: Ord c => (a -> b -> c) -> [a] -> [b] -> [c]
setFunc fn xs ys = mySort (cartesianFunc fn xs ys)
Testing:
λ>
λ> cartesianFunc (*) [1,2,4] [1,3,9]
[1,3,9,2,6,18,4,12,36]
λ>
λ> mySort $ cartesianFunc (*) [1,2,4] [1,3,9]
[1,2,3,4,6,9,12,18,36]
λ>
λ> setFunc (*) [1,2,4] [1,3,9]
[1,2,3,4,6,9,12,18,36]
λ>
Related
I want to write a function that takes a list of sorted lists, then merges everything together and sorts them again.
I managed to write this so far:
merge_:: Ord a => [[a]] -> [a] --takes in the list and merges it
merge_ [] = []
merge_ (x:xs) = x ++ merge_ xs
isort:: Ord a => [a] -> [a] --Sorts a list
isort [] = []
isort (a:x) = ins a (isort x)
where
ins a [] = [a]
ins a (b:y) | a<= b = a:(b:y)
| otherwise = b: (ins a y)
I haven't been able to find a way to combine these two in one function in a way that makes sense. Note that I'm not allowed to use things such as ('.', '$'..etc) (homework)
We start simple. How do we merge two sorted lists?
mergeTwo :: Ord a => [a] -> [a] -> [a]
mergeTwo [] ys = ys
mergeTwo xs [] = xs
mergeTwo (x:xs) (y:ys)
| x <= y = x : mergeTwo xs (y:ys)
| otherwise = y : mergeTwo (x:xs) ys
How do we merge multiple? Well, we start with the first and the second and merge them together. Then we merge the new one and the third together:
mergeAll :: Ord a => [[a]] -> [a]
mergeAll (x:y:xs) = mergeAll ((mergeTwo x y) : xs)
mergeAll [x] = x
mergeAll _ = []
Allright. Now, to sort all elements, we need to create a list from every element, and then merge them back. Let's write a function that creates a list for a single item:
toList :: a -> [a]
toList x = -- exercise
And now a function to wrap all elements in lists:
allToList :: [a] -> [[a]]
allToList = -- exercise
And now we're done. We simply need to use allToList and then mergeAll:
isort :: Ord a => [a] -> [a]
isort xs = mergeAll (allToList xs)
Note that this exercise got a lot easier since we've split it into four functions.
Exercises (which might not be possible for you(r homework))
Write toList and allToList.
Try a list comprehension for allToList. Try a higher order function for allToList.
Write isort point-free (with (.)).
Check whether there is already a toList function with the same type. Use that one.
Rewrite mergeAll using foldr
Try this (not tested):
merge :: Ord a => [a] -> [a] -> [a]
merge [] l1 = l1
merge l1 [] = l1
merge (e1:l1) (e2:l2)
| e1<e2 = e1:merge l1 (e2:l2)
| otherwise = e2:merge (e1:l1) l2
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
Suppose I have two lists A and B of the same length. I want to keep elements in A which are greater than corresponding elements in B. Let A=[1,5,8], B=[2,4,9], the result should be [5] because 1<2, 5>4, 8<9.
I come up with a solution. Let C=zip A B, then filter C, finally get result by taking fst of each element in C. It's not so elegant. Is there a simpler way?
Code:
map fst (filter (\ x-> (fst x) > (snd x)) (zip a b))
Your described solution looks fine to me.
An alternative which is not necessarily better:
import Data.Maybe
import Control.Monad
catMaybes $ zipWith (\a b -> guard (a>b) >> return a) list1 list2
According to the desugaring of monad comprehensions this should also work
{-# LANGUAGE MonadComprehensions #-}
[ a | ( a <- list1 | b <- list2 ), a > b ]
... but in practice it does not. It is a pity because I find it quite elegant.
I wonder whether I got it wrong or it is a GHC bug.
I was working on something similar and as a newbie this is the best I came up with:
filterGreaterThan xs ys = do (x,y) <- zip xs ys
guard (x > y)
return x
This solution is easier to reason about than the others. The do notation really shines here.
I'm not sure how your code looks but the following function look quite elegant to me:
greater :: Ord a => [a] -> [a] -> [a]
greater xs = map fst . filter ((>) <$> fst <*> snd) . zip xs
example :: [Int]
example = greater [1,5,8] [2,4,9] -- result is [5]
This pattern is well known in the Lisp community as the decorate-process-undecorate pattern.
A recursive approach, not so elegant as (any) of the other approaches, this relies on no explicit zipping and we get the result in one pass,
greater :: Ord a => [a] -> [a] -> [a]
greater [] [] = []
greater (x:xs) (y:ys)
| x > y = x : greater xs ys
| otherwise = greater xs ys
If you want to generalize this idea nicely, I would recommend looking to mapMaybe:
mapMaybe
:: (a -> Maybe b)
-> [a] -> [b]
Applying that idea to zipWith yields
zipWithMaybe
:: (a -> b -> Maybe c)
-> [a] -> [b] -> [c]
zipWithMaybe f xs ys =
[c | Just c <- zipWith f xs ys]
Now you can write your function
keepGreater :: Ord a => [a] -> [a] -> [a]
keepGreater = zipWithMaybe $
\x y -> x <$ guard (x > y)
Is it really worth the trouble? For lists, probably not. But something like this turns out to be useful in the context of merges for Data.Map.
Pretty similar to #chi's solution with Lists concant:
concat $ zipWith (\a b -> last $ []:[[a] | a > b]) as bs
I just wanted to multiply two lists element by element, so I'd pass (*) as the first argument to that function:
apply :: Num a => (a -> a -> a) -> [a] -> [a] -> [a]
apply f xs ys = [f (xs !! i) (ys !! i) | i <- [0..(length xs - 1)]]
I may be asking a silly question, but I actually googled a lot for it and just couldn't find. Thank you, guys!
> :t zipWith
zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
> zipWith (*) [1,2,3] [4,5,6]
[4,10,18]
It's the eighth result provided by Hoogle when queried with your type
(a -> a -> a) -> [a] -> [a] -> [a]
Moreover, when you need to implement your own function, use list !! index only as a last resort, since it usually leads to a bad performance, having a cost of O(index). Similarly, length should be used only when necessary, since it needs to scan the whole list.
In the zipWith case, you can avoid both and proceed recursively in a natural way: it is roughly implemented as
zipWith _ [] _ = []
zipWith _ _ [] = []
zipWith f (x:xs) (y:ys) = f x y : zipWith f xs ys
Note that this will only recurse as much as needed to reach the end of the shortest list. The remaining part of the longer list will be discarded.
I'm doing a bit of self study on functional languages (currently using Haskell). I came across a Haskell based assignment which requires defining map and filter in terms of foldr. For the life of me I'm not fully understanding how to go about this.
For example when I define a map function like:
map' :: (a -> b) -> [a] -> [b]
map' f [] = []
map' f (x:xs) = foldr (\x xs -> (f x):xs) [] xs
I don't know why the first element of the list is always ignored. Meaning that:
map' (*2) [1,2,3,4]
results in [4,6,8] instead of [2,4,6,8]
Similarly, my filter' function:
filter' :: (a -> Bool) -> [a] -> [a]
filter' p [] = []
filter' p (x:xs) = foldr (\x xs -> if p x then x:xs else xs ) [] xs
when run as:
filter' even [2,3,4,5,6]
results in [4,6] instead of [2,4,6]
Why would this be the case? And how SHOULD I have defined these functions to get the expected results? I'm assuming something is wrong with my lambda expressions...
I wish I could just comment, but alas, I don't have enough karma.
The other answers are all good ones, but I think the biggest confusion seems to be stemming from your use of x and xs.
If you rewrote it as
map' :: (a -> b) -> [a] -> [b]
map' f [] = []
map' f (x:xs) = foldr (\y ys -> (f y):ys) [] xs
you would clearly see that x is not even mentioned on the right-hand side, so there's no way that it could be in the solution.
Cheers
For your first question, foldr already has a case for the empty list, so you need not and should not provide a case for it in your own map.
map' f = foldr (\x xs -> f x : xs) []
The same holds for filter'
filter' p = foldr (\x xs -> if p x then x : xs else xs) []
Nothing is wrong with your lambda expressions, but there is something wrong with your definitions of filter' and map'. In the cons case (x:xs) you eat the head (x) away and then pass the tail to foldr. The foldr function can never see the first element you already ate. :)
Alse note that:
filter' p = foldr (\x xs -> if p x then x : xs else xs) []
is equivalent (η-equivalent) to:
filter' p xs = foldr (\x xs -> if p x then x : xs else xs) [] xs
I would define map using foldr and function composition as follows:
map :: (a -> b) -> [a] -> [b]
map f = foldr ((:).f) []
And for the case of filter:
filter :: (a -> Bool) -> [a] -> [a]
filter p = foldr (\x xs -> if p x then x:xs else xs) []
Note that it is not necessary to pass the list itself when defining functions over lists using foldr or foldl.
The problem with your solution is that you drop the head of the list and then apply the map over the list and
this is why the head of the list is missing when the result is shown.
In your definitions, you are doing pattern matching for x:xs, which means, when your argument is [1,2,3,4], x is bound to 1 and xs is bound to the rest of the list: [2,3,4].
What you should not do is simply throw away x: part. Then your foldr will be working on whole list.
So your definitions should look as follows:
map' :: (a -> b) -> [a] -> [b]
map' f [] = []
map' f xs = foldr (\x xs -> (f x):xs) [] xs
and
filter' :: (a -> Bool) -> [a] -> [a]
filter' p [] = []
filter' p xs = foldr (\x xs -> if p x then x:xs else xs ) [] xs
I am new to Haskell (in fact I've found this page asking the same question) but this is my understanding of lists and foldr so far:
lists are elements that are linked to the next element with the cons (:) operator. they terminate with the empty list []. (think of it as a binary operator just like addition (+) 1+2+3+4 = 10, 1:2:3:4:[] = [1,2,3,4]
foldr function takes a function that takes two parameters. this will replace the cons operator, which will define how each item is linked to the next.
it also takes the terminal value for the operation, which can be tought as the initial value that will be assigned to the empty list. for cons it is empty list []. if you link an empty list to any list the result is the list itself. so for a sumfunction it is 0. for a multiply function it is 1, etc.
and it takes the list itself
So my solution is as follows:
filter' p = foldr (\x n -> if p x then x : n else n) []
the lambda expression is our link function, which will be used instead of the cons (:) operator. Empty list is our default value for an empty list. If predicate is satisfied we link to the next item using (:) as normal, else we simply don't link at all.
map' f = foldr (\x n -> f x : n) []
here we link f x to the next item instead of just x, which would simply duplicate the list.
Also, note that you don't need to use pattern matching, since we already tell foldr what to do in case of an empty list.
I know this question is really old but I just wanted to answer it anyway. I hope it is not against the rules.
A different way to think about it - foldr exists because the following recursive pattern is used often:
-- Example 1: Sum up numbers
summa :: Num a => [a] -> a
summa [] = 0
summa (x:xs) = x + suma xs
Taking the product of numbers or even reversing a list looks structurally very similar to the previous recursive function:
-- Example 2: Reverse numbers
reverso :: [a] -> [a]
reverso [] = []
reverso (x:xs) = x `op` reverso xs
where
op = (\curr acc -> acc ++ [curr])
The structure in the above examples only differs in the initial value (0 for summa and [] for reverso) along with the operator between the first value and the recursive call (+ for summa and (\q qs -> qs ++ [q]) for reverso). So the function structure for the above examples can be generally seen as
-- Generic function structure
foo :: (a -> [a] -> [a]) -> [a] -> [a] -> [a]
foo op init_val [] = init_val
foo op init_val (x:xs) = x `op` foo op init_val xs
To see that this "generic" foo works, we could now rewrite reverso by using foo and passing it the operator, initial value, and the list itself:
-- Test: reverso using foo
foo (\curr acc -> acc ++ [curr]) [] [1,2,3,4]
Let's give foo a more generic type signature so that it works for other problems as well:
foo :: (a -> b -> b) -> b -> [a] -> b
Now, getting back to your question - we could write filter like so:
-- Example 3: filter
filtero :: (a -> Bool) -> [a] -> [a]
filtero p [] = []
filtero p (x:xs) = x `filterLogic` (filtero p xs)
where
filterLogic = (\curr acc -> if (p curr) then curr:acc else acc)
This again has a very similar structure to summa and reverso. Hence, we should be able to use foo to rewrite it. Let's say we want to filter the even numbers from the list [1,2,3,4]. Then again we pass foo the operator (in this case filterLogic), initial value, and the list itself. filterLogic in this example takes a p function, called a predicate, which we'll have to define for the call:
let p = even in foo (\curr acc -> if (p curr) then curr:acc else acc) [] [1,2,3,4]
foo in Haskell is called foldr. So, we've rewritten filter using foldr.
let p = even in foldr (\curr acc -> if (p curr) then curr:acc else acc) [] [1,2,3,4]
So, filter can be written with foldr as we've seen:
-- Solution 1: filter using foldr
filtero' :: (a -> Bool) -> [a] -> [a]
filtero' p xs = foldr (\curr acc -> if (p curr) then curr:acc else acc) [] xs
As for map, we could also write it as
-- Example 4: map
mapo :: (a -> b) -> [a] -> [b]
mapo f [] = []
mapo f (x:xs) = x `op` (mapo f xs)
where
op = (\curr acc -> (f curr) : acc)
which therefore can be rewritten using foldr. For example, to multiply every number in a list by two:
let f = (* 2) in foldr (\curr acc -> (f curr) : acc) [] [1,2,3,4]
So, map can be written with foldr as we've seen:
-- Solution 2: map using foldr
mapo' :: (a -> b) -> [a] -> [b]
mapo' f xs = foldr (\curr acc -> (f curr) : acc) [] xs
Your solution almost works .)
The problem is that you've got two differend bindings for x in both your functions (Inside the patternmatching and inside your lambda expression), therefore you loose track of the first Element.
map' :: (a -> b) -> [a] -> [b]
map' f [] = []
map' f (x:xs) = foldr (\x xs -> (f x):xs) [] (x:xs)
filter' :: (a -> Bool) -> [a] -> [a]
filter' p [] = []
filter' p (x:xs) = foldr (\x xs -> if p x then x:xs else xs ) [] (x:xs)
This should to the trick :). Also: you can write your functions pointfree style easily.
*Main> :{
*Main| map' :: (a -> b) -> [a] -> [b]
*Main| map' = \f -> \ys -> (foldr (\x -> \acc -> f x:acc) [] ys)
*Main| :}
*Main> map' (^2) [1..10]
[1,4,9,16,25,36,49,64,81,100]
*Main> :{
*Main| filter' :: (a -> Bool) -> [a] -> [a]
*Main| filter' = \p -> \ys -> (foldr (\x -> \acc -> if p x then x:acc else acc) [] ys)
*Main| :}
*Main> filter' (>10) [1..100]
In the above snippets acc refers to accumulator and x refers to the last element.
Everything is correct in your lambda expressions. The problem is you are missing the first element in the list. If you try,
map' f (x:xs) = foldr (\x xs -> f x:xs) [] (x:xs)
then you shouldn't miss the first element anymore. The same logic applies to filter.
filter' p (x:xs) = foldr(\ y xs -> if p y then y:xs else xs) [] (x:xs)