Related
I want to write a recursive function that gets two lists + a conditional as input, and outputs all possible tuples with one element each from the 1st and 2nd lists that satisfy the condition.
It should look something like this:
Combine [1,2,3] [5,6,7] (\a b -> a+b > 7) -> [(1,7),(2,6),(2,7),(3,5),(3,6),(3,7)]
I got this atm:
Combine:: [a] -> [b] -> [(a, b)]
Combine [] ys = []
Combine xs [] = []
Combine (x:xs) (y:ys) = (x,y) : Combine xs ys
However, it does not yet create all possible combinations and does not filter by condition. I really don't know how to figure this out.
Thanks in advance
You don't need a recursive function, but you need a higher order function.
combinationsFilter :: (a -> b -> Bool) -> [a] -> [b] -> [(a,b)]
combinationsFilter f as bs = filter (uncurry f) [(a, b) | a <- as, b <- bs]
[(a, b) | a <- as, b <- bs] generates all combinations of a and b.
filter... just filters the list by condition.
uncurry needed if you want pass a function with type (a -> b -> c), but not ((a, b) -> c). It converts one to the other.
I am new to Haskell and I want to extract the maximum element from a given List so that I end up with the maximum element x and the remaining list xs (not containing x). It can be assumed that the elements of the list are unique.
The type of function I want to implement is somewhat like this:
maxElement :: (Ord b) => (a -> b) -> [a] -> (a, [a])
Notably, the first argument is a function that turns an element into a comparable form. Also, this function is non-total as it would fail given an empty List.
My current approach fails to keep the elements in the remainder list in place, meaning given [5, 2, 4, 6] it returns (6, [2, 4, 5]) instead of (6, [5, 2, 4]). Furthermore, it feels like there should be a nicer looking solution.
compareElement :: (Ord b) => (a -> b) -> a -> (b, (a, [a])) -> (b, (a, [a]))
compareElement p x (s, (t, ts))
| s' > s = (s', (x, t:ts))
| otherwise = (s, (t, x:ts))
where s' = p x
maxElement :: (Ord b) => (a -> b) -> [a] -> (a, [a])
maxElement p (t:ts) = snd . foldr (compareElement p) (p t, (t, [])) $ ts
UPDATE
Thanks to the help of the answer of #Ismor and the comment #chi I've updated my implementation and I feel happy with the result.
maxElement :: (Ord b) => (a -> b) -> [a] -> Maybe (b, a, [a], [a])
maxElement p =
let
f x Nothing = Just (p x, x, [], [x])
f x (Just (s, m, xs, ys))
| s' > s = Just (s', x, ys, x:ys)
| otherwise = Just (s, m, x:xs, x:ys)
where s' = p x
in
foldr f Nothing
The result is either Nothing when the given list is empty or Maybe (_, x, xs, _). I could write another "wrapper" function with the originally intended type and call maxElement under the hood, but I believe this also ok.
This answer is more of a personal advise than a proper answer. As a rule of thumb, whenever you find yourself trying to write a loop with an accumulator (as in this case), try to write it in this form
foldr updateAccumulator initialAccumulator --use foldl' if it is better for your use case`
then, follow the types to complete It as shown below
Step 1
Write undefined where needed. You know the function should look like this
maxElement :: (Ord b) => (a -> b) -> [a] -> (a, [a])
maxElement f xs = foldr updateAccumulator initalAccumulator xs
where
updateAccumulator = undefined
initialAccumulator = undefined
Step 2
"Chase the type". Meaning that using the type of maxElement and foldr you can
deduce the types of updateAccumulator and initialAccumulator. Try to reduce polymorphism as much as you can. In this case:
You know foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b
You know your Foldable is [] so It'd be easier to substitute
Hence foldr :: (a -> b -> b) -> b -> [a] -> b
Because you want foldr to produce (a, [a]) you know b ~ (a, [a])
etc... keep going until you know what types your functions have. You can use ghc typed holes in this process, which is a very nice feature
maxElement :: (Ord b) => (a -> b) -> [a] -> (a, [a])
maxElement f xs = foldr updateAccumulator initalAccumulator xs
where
-- Notice that you need to enable an extension to write type signature in where clause
-- updateAccumulator :: a -> (a, [a]) -> (a, [a])
updateAccumulator newElement (currentMax, currentList) = undefined
-- initialAccumulator :: (a, [a])
initialAccumulator = undefined
Step 3
Now, writing down the function should be easier. Below I leave some incomplete parts for you to fill
maxElement :: (Ord b) => (a -> b) -> [a] -> (a, [a])
maxElement f xs = foldr updateAccumulator initalAccumulator xs
where
-- updateAccumulator :: a -> (a, [a]) -> (a, [a])
updateAccumulator newElement (currentMax, currentList) =
if f newElement > f currentMax
then undefined -- How does the accumulator should look when the new element is bigger than the previous maximum?
else undefined
-- initialAccumulator :: (a, [a])
initialAccumulator = undefined -- Tricky!, what does happen if xs is empty?
Hope this clarifies some doubts, and understand I don't give you a complete answer.
I don't know if you were trying to avoid using certain library functions, but Data.List has a maximumBy and deleteBy that do exactly what you want:
import Data.Function (on)
import Data.List (deleteBy, maximumBy)
import Data.Ord (comparing)
maxElement :: (Ord b) => (a -> b) -> [a] -> (a, [a])
maxElement f xs = (max, remaining) where
max = maximumBy (comparing f) xs
remaining = deleteBy ((==) `on` f) max xs
Thanks to the help of the answer of #Ismor and the comment #chi I've updated my implementation and I feel happy with the result.
maxElement :: (Ord b) => (a -> b) -> [a] -> Maybe (b, a, [a], [a])
maxElement p =
let
f x Nothing = Just (p x, x, [], [x])
f x (Just (s, m, xs, ys))
| s' > s = Just (s', x, ys, x:ys)
| otherwise = Just (s, m, x:xs, x:ys)
where s' = p x
in
foldr f Nothing
The result is either Nothing when the given list is empty or Maybe (_, x, xs, _). I could write another "wrapper" function with the originally intended type and call maxElement under the hood, but I believe this is also ok.
Construct the list of all the "zippers" over the input list, then take the maximumBy (comparing (\(_,x,_) -> foo x)) of it, where foo is your Ord b => a -> b function, then reverse-append the first half to the second and put it in a tuple together with the middle element.
A zipper over a list xs is a triple (revpx, x, suffx) where xs == reverse revpx ++ [x] ++ suffx:
> :t comparing (\(_,x,_) -> x)
comparing (\(_,x,_) -> x)
:: Ord a => (t, a, t1) -> (t, a, t1) -> Ordering
Constructing the zippers list is an elementary exercise (see the function picks3 there).
About your edited solution, it can be coded as a foldr over the tails so it's a bit clearer what's going on there:
maxElement :: (Ord b) => (a -> b) -> [a] -> Maybe (b, a, [a])
maxElement p [] = Nothing
maxElement p xs = Just $ foldr f undefined (tails xs)
where
f [x] _ = (p x, x, [])
f (x:xs) (b, m, ys)
| b' > b = (b', x, xs) -- switch over
| otherwise = (b, m, x:ys)
where b' = p x
It's also a bit cleaner as it doesn't return the input list's copy for no apparent reason, as your version did since it used it for internal purposes.
Both ways are in fact emulating a paramorphism.
I am trying to convert a list to a data.map so that from a list like:
mylist = ["one","one","two","three","two","two","three","four","four","four","four","five","five","two"]
I get something like:
("one", 2) ("two", 4) ...
I am trying following code:
import qualified Data.Map as Map
import Data.List
list2dict [] mymap = print mymap
list2dict [y:ys] mymap = do
if (Map.lookup y mymap) /= Nothing
then list2dict [ys] $ Map.insert y ((Map.lookup y) + 1) mymap
else list2dict [ys] $ Map.insert y 1 mymap
mylist = ["one","one","two","three","two","two","three","four","four","four","four","five","five","two"]
main = do
list2dict (sort mylist) $ Map.empty
However, I am getting following error:
soq_list2dict.hs:5:1: error:
• Non type-variable argument
in the constraint: Show (Map.Map k a -> Maybe a)
(Use FlexibleContexts to permit this)
• When checking the inferred type
list2dict :: forall a k.
(Show (Map.Map k a -> Maybe a), Show k, Ord k,
Num (Map.Map k a -> Maybe a), Eq (Map.Map k a -> Maybe a)) =>
[[k]] -> Map.Map k (Map.Map k a -> Maybe a) -> IO ()
How can this be solved?
Edit: using (y:ys) instead of [y:ys] gives following error:
soq_list2dict.hs:5:1: error:
• Occurs check: cannot construct the infinite type: k ~ [k]
Expected type: [[k]] -> Map.Map k (Map.Map k a -> Maybe a) -> IO ()
Actual type: [k] -> Map.Map k (Map.Map k a -> Maybe a) -> IO ()
• Relevant bindings include
list2dict :: [[k]] -> Map.Map k (Map.Map k a -> Maybe a) -> IO ()
(bound at soq_list2dict.hs:5:1)
Willem Van Onsem already pointed out the first problem in a comment: you used [y:ys] instead of (y:ys). The second problem is that you used [ys] instead of just ys in two places. The third problem is that you say ((Map.lookup y) + 1), which creates a nonsensical type. (Even if you had used ((Map.lookup y mymap) + 1) instead, which is closer to correct, you still would have just gotten a different error.) This way will work instead:
list2dict (y:ys) mymap = case Map.lookup y mymap of
Just x -> list2dict ys $ Map.insert y (x + 1) mymap
Nothing -> list2dict ys $ Map.insert y 1 mymap
Note that I pattern-match on the Maybe rather than testing it with if and then trying to extract the value separately after that.
You made a classic error: a non-empty list has as pattern (x:xs) (notice the empty brackets). But you make things too complicated here.
You can implement this with a foldr pattern, that can convert any (Ord a, Foldable f) => f a to a (Ord a, Integral i) => Map a i:
import Data.Map(Map, alter, empty)
import Data.Maybe(maybe)
toCounter :: (Ord a, Foldable f, Integral i) => f a -> Map a i
toCounter = foldr (alter (Just . maybe 1 (1+))) empty
We thus start with an empty map, and for each item in the Foldable, we perform an alter where, in case the item already exists (then it gives us a Just n, we return a Just (n+1), and for a Nothing we fallback on 1.
Since it works on (Ord a, Foldable f) => f a, you can make a "counter" for anything of a type that is an instance of the Ord typeclass, and is stored in a object of a type that is an instance of a Foldable. So it can count items in a list, Maybe (well this has exactly one or no item), a Tree, etc.
For example:
*Main> toCounter ["one","one","two","three","two","two","three","four","four","four","four","five","five","two"]
fromList [("five",2),("four",4),("one",2),("three",2),("two",4)]
A shorter version, that works on lists is one written by #DavidFletcher:
import Data.Map(Map, fromListWith)
toCounter :: (Ord a, Integral i) => [a] -> Map a i
toCounter = fromListWith (+) . map (flip (,) 1)
we can however use toList to let it work with Foldables as well:
import Data.Foldable(toList)
import Data.Map(Map, fromListWith)
toCounter :: (Ord a, Foldable f, Integral i) => f a -> Map a i
toCounter = fromListWith (+) . map (flip (,) 1) . toList
So basically I have a list of tuples [(a,b)], from which i have to do some filtering. One job is to remove inverted duplicates such that if (a,b) and (b,a) exist in the list, I only take one instance of them. But the list comprehension has not been very helpful. How to go about this in an efficient manner?
Thanks
Perhaps an efficient way to do so (O(n log(n))) would be to track the tuples (and their reverses) already added, using Set:
import qualified Data.Set as Set
removeDups' :: Ord a => [(a, a)] -> Set.Set (a, a) -> [(a, a)]
removeDups' [] _ = []
removeDups' ((a, b):tl) s | (a, b) `Set.member` s = removeDups' tl s
removeDups' ((a, b):tl) s | (b, a) `Set.member` s = removeDups' tl s
removeDups' ((a, b):tl) s = ((a, b):rest) where
s' = Set.insert (a, b) s
rest = removeDups' tl s'
removeDups :: Ord a => [(a, a)] -> [(a, a)]
removeDups l = removeDups' l (Set.fromList [])
The function removeDups calls the auxiliary function removeDups' with the list, and an empty set. For each pair, if it or its inverse are in the set, it is passed; otherwise, both it and its inverses are added, and the tail is processed. \
The complexity is O(n log(n)), as the size of the set is at most linear in n, at each step.
Example
...
main = do
putStrLn $ show $ removeDups [(1, 2), (1, 3), (2, 1)]
and
$ ghc ord.hs && ./ord
[1 of 1] Compiling Main ( ord.hs, ord.o )
Linking ord ...
[(1,2),(1,3)]
You can filter them using your own function:
checkEqTuple :: (a, b) -> (a, b) -> Bool
checkEqTuple (x, y) (x', y') | (x==y' && y == x') = True
| (x==x' && y == y') = True
| otherwise = False
then use nubBy
Prelude Data.List> nubBy checkEqTuple [(1,2), (2,1)]
[(1,2)]
I feel like I'm repeating myself a bit, but that's okay. None of this code had been tested or even compiled, so there may be bugs. Suppose we can impose an Ord constraint for efficiency. I'll start with a limited implementation of sets of pairs.
import qualified Data.Set as S
import qualified Data.Map.Strict as M
newtype PairSet a b =
PS (M.Map a (S.Set b))
empty :: PairSet a b
empty = PS M.empty
insert :: (Ord a, Ord b)
=> (a, b) -> PairSet a b -> PairSet a b
insert (a, b) (PS m) = PS $ M.insertWith S.union a (S.singleton b) m
member :: (Ord a, Ord b)
=> (a, b) -> PairSet a b -> Bool
member (a, b) (PS m) =
case M.lookup a m of
Nothing -> False
Just s -> S.member b s
Now we just need to keep track of which pairs we've seen.
order :: Ord a => (a, a) -> (a, a)
order p#(a, b)
| a <= b = p
| otherwise = (b, a)
nubSwaps :: Ord a => [(a,a)] -> [(a,a)]
nubSwaps xs = foldr go (`seq` []) xs empty where
go p r s
| member op s = r s
| otherwise = p : r (insert op s)
where op = order p
If a and b are ordered and compareable, you could just do this:
[(a,b) | (a,b) <- yourList, a<=b]
Yes this is a uni assignment question, so please do not just give me the answer, I need to be able to learn what it is and how to do it, (mostly because there are further questions and I need to develop an understanding of the Haskell language to do them!
THE QUESTION:
join :: Eq a => [(a,b)] -> [(a,c)] -> [(a,b,c)].
join takes two lists of pairs, and returns a single list of triples. A triple
is generated only when there exists a member of both argument lists
that have the same first element. The list elements are not sorted. This
is the same semantics as the relational algebra natural join operation.
For example:
join [(2,"S"),(1,"J")] [(2,True),(3,False)])
Should produce the output [(2,"S",True)]
join [(2,"S"),(1,"J")] [(2,1),(2,2),(3,4)])
Should produce the output [(2,"S",1),(2,"S",2)]
My problem
My main problem is trying to figure out how to create a new list from the 2 lists that are input, which have different attributes.
What I have so far:
join :: Eq a => [(a,b)] -> [(a,c)] -> [(a,b,c)]
join xs [] = xs
join [] ys = ys
join (x:xs) (y:ys) = (x ++ snd(head[x]) ++ snd(head[y]) ++ []) join xs ys
The resulting error:
Type error in explicitly typed binding
*** Term : merge
*** Type : [(a,b)] -> [(a,c)] -> [(a,b)]
*** Does not match : [(a,b)] -> [(a,c)] -> [(a,b,c)]
Other notes:
I have tried several variations of the (x ++ snd(head[x]) ++ snd(head[y]) ++ []) section of code, with the results being mostly the same or simular error message!
Your types do not match
join :: Eq a => [(a,b)] -> [(a,c)] -> [(a,b,c)]
join xs [] = xs
join [] ys = ys
-- ^^^^ three different types involved!
xs and ys has type [(a, b)] and [(a, c)] then, they can not be the resultant type [(a,b,c)].
You must to create your resultant data from xs and ys, something like
join ? ? = ... (a, b, c) ...
Can you figure that?
Tip: what is the body of
makeTuple :: (a, b) -> (a, c) -> (a, b, c)
-- ^ ^
-- : |
-- : +-- only one value exists you can put here
-- :
-- +····· only one value exists you can put here
the only two possible functions are
makeTuple (x1, y) (x2, z) = (x1, y, z)
and
makeTuple (x1, y) (x2, z) = (x2, y, z)
In the same way, your join must to preserve the resultant type.
From signature
join :: Eq a => [(a,b)] -> [(a,c)] -> [(a,b,c)]
you know type a is equatable and you know nothing about b and c types.
A simple way to do this is
join xs ys = [(xa, xb, yc) | (xa, xb) <- xs, (ya, yc) <- ys, xa == ya]
-- ^^^^^^^^
-- from `Eq a` constraint