I have this simple function which returns a list of pairs with the adjacents elements of a list.
adjacents :: [a] -> [(a,a)]
adjacents (x:y:xs) = [(x,y)] ++ adjacents (y:xs)
adjacents (x:xs) = []
I'm having problems trying to write adjacents using foldr. I've done some research but nothing seems to give me a hint. How can it be done?
Tricky folds like this one can often be solved by having the fold build up a function rather than try to build the result directly.
adjacents :: [a] -> [(a, a)]
adjacents xs = foldr f (const []) xs Nothing
where f curr g (Just prev) = (prev, curr) : g (Just curr)
f curr g Nothing = g (Just curr)
Here, the idea is to let the result be a function of type Maybe a -> [(a, a)] where the Maybe contains the previous element, or Nothing if we're at the beginning of the list.
Let's take a closer look at what's going on here:
If we have both a previous and a current element, we make a pair and pass the current element to the result of the recursion, which is the function which will generate the tail of the list.
f curr g (Just prev) = (prev, curr) : g (Just curr)
If there is no previous element, we just pass the current one to the next step.
f curr g Nothing = g (Just curr)
The base case const [] at the end of the list just ignores the previous element.
By doing it this way, the result is as lazy as your original definition:
> adjacents (1 : 2 : 3 : 4 : undefined)
[(1,2),(2,3),(3,4)*** Exception: Prelude.undefined
I don't think your function is a good fit for a fold, because it looks at two elements rather than one.
I think the best solution to the problem is
adjacents [] = []
adjacents xs = zip xs (tail xs)
But we can shoehorn it into a travesty of a fold if you like. First an auxilliary function.
prependPair :: a -> [(a,a)] -> [(a,a)]
prependPair x [] = [(x,b)] where b = error "I don't need this value."
prependPair x ((y,z):ys) = ((x,y):(y,z):ys)
adjacents' xs = init $ foldr prependPair [] xs
I feel like I've cheated slightly by making and throwing
away the last element with the error value, but hey ho, I already said I don't think
foldr is a good way of doing this, so I guess this hack is an example of it not being a fold.
You can also try unfoldr instead of foldr.
import Data.List
adjacents xs = unfoldr f xs where
f (x:rest#(y:_)) = Just ((x,y), rest)
f _ = Nothing
Related
I am a newbie to Haskell and I wrote the following code
module RememberMap (rememberMap) where
rememberMap :: (a -> b -> (a, c)) -> a -> [b] -> [c]
rememberMap f acc xs = go acc xs []
where
go acc [x] carry = carry <> [step]
where
(_, step) = f acc x
go acc (x:xs) carry = go accStep xs (carry <> [step])
where
(accStep, step) = f acc x
I wrote this contaminator with the Intent to help me with the most Common difficulty that i have when writing my Haskell code, That is that I recurrently find myself willing to map something (specially in CodeWarrior's Katas) like to map something, but that something required knowledge of the elements before it. But it had the problem of being non-streaming, ergo, it does no allow me to use lazy proprieties of Haskell with it, thus I would like to know if (a) there is already a solution to this problem (preferably Arrows) or (b) how to make it lazy.
To make the function stream you need to have the cons operator outside the recursive call, so a caller can see the first element without the whole recursion needing to happen. So you expect it to look something like:
rememberMap f acc (x:xs) = element : ... recursion ...
Once you understand this there is not much more to do:
rememberMap _ _ [] = []
rememberMap f acc (x:xs) = y : rememberMap f acc' xs
where
(acc', y) = f acc x
You can make an auxiliary function to avoid passing f around if you want, but there's no reason for it to have the extra list that you called carry.
There are mapAccumL and traverse with the lazy State monad.
I'm working with relations and I want to find whether a relation is symmetric.
To find that a relation is symmetric, we need to find two tuples such that: [(a,b), (b,a)].
This is what I've got so far:
simmetry:: Eq a => [(a,a)] -> [a]
simmetry [] = []
simmetry (x:xs)
| (fst x `elem` map snd xs) && (snd x `elem` map fst xs) = fst x : (simmetry xs)
| otherwise = simmetry xs
What this function does is, it grabs a tuple x and checks that it finds its first element in another tuple as the second position, as well as checking that the second element is in another tuple as the first position.
However I'm missing out on the part where I have to check that the other tuple is the same one for both conditions. With my code, something like this: [(a,b),(b,c),(d,a)] would work.
P.D: simmetry returns [a] for testing purposes.
I'm out of ideas, any tips are highly appreciated!
What you want to check is: for every tuple (x,y) in the list, (y,x) should also be present. You can express that quite directly in Haskell:
isSymmetric :: Eq a => [(a,a)] -> Bool
isSymmetric l = all (\(x,y) -> (y,x)`elem`l) l
This is actually doing some redundant work because it always also goes over (x,y) itself, which your not really interested in, but it doesn't really matter. However it's a good exercise to design this in a way so it doesn't go over the element itself; for this it's helpful to use an auxiliary function
foci :: [a] -> [(a,[a])]
witht the behaviour
foci [p,q,r] ≡ [(p,[q,r]), (q,[p,r]), (r,[p,q])]
Then you left with an all over the foci of the input list, i.e.
isSymmetric = all _ . foci
With what #Rik Van Toor said:
simmetry:: Eq a => [(a,a)] -> [a]
simmetry [] = []
simmetry (x:xs)
| (snd x, fst x) `elem` xs = fst x : (simmetry xs)
| otherwise = simmetry xs
My professor gave me an example to get last element in the list using "laste" function:
he stated that: definition in the form of “laste xs = …” is not acceptable, whereas definition in the form of “laste = …” is acceptable.
I have tried something like this: Please correct me if my solution is wrong according to problem statement.
laste :: [a] -> Maybe a
laste [] = Nothing
laste (x:[]) = Just x
laste (x:xs) = laste xs
But this gives me answer for example:
ghci>laste[1,2,3,4]
Just 4
I want to get rid of this "Just".
Is there any solution to remove Just?
You would need to change the signature of the function to return a simple element.
The thing is that you would need to return an error in case of empty list.
laste :: [a] -> a
laste [] = error "Can't handle empty lists." -- or some other error message
laste [x] = x
laste (x:xs) = laste xs
While Charmini2's answer is functionally correct, it doesn't solve the problem of retrieving the last element in pointfree form. Consider
laste :: [a] -> a
laste = foldr1 (\_ a -> a)
It works according to specs as foldr1 expects a non-empty list. Intuition for why it returns the last element in the list can be gotten from the observation that foldr1 replaces every (:) in the structure of the list with the lambda in the above equation, which basically selects the rightmost of two elements. Repeat, and you get the last.
I think your professor meant was that you need to re-implement the Prelude function last
in a point-free style.
non point-free example:
filterEven xs = filter even xs
point-free exapmle:
filterEven = filter even
point-free examples of last:
lastv1 = (head . reverse)
lastv2 = foldl1 (\acc x -> x)
lastv3 = foldr1 (\x acc -> acc)
lastv4 = \(x:xs) -> if null xs then x else lastv4 xs
lastv5 = \e -> case e of
[x] -> x
(_:xs) -> lastv5 xs
otherwise -> error "empty list"
Here a possible working solution:
last' :: [a] -> a
last' [] = error "empty"
last' (x:[]) = x
last' (x:xs) = last' xs
im searching for a solution for my Haskell class.
I have a list of numbers and i need to return SUM for every part of list. Parts are divided by 0. I need to use FOLDL function.
Example:
initial list: [1,2,3,0,3,4,0,5,2,1]
sublist [[1,2,3],[3,4],[5,2,1]]
result [6,7,7]
I have a function for finding 0 in initial list:
findPos list = [index+1 | (index, e) <- zip [0..] list, e == 0]
(returns [4,6] for initial list from example)
and function for making SUM with FOLDL:
sumList list = foldl (+) 0 list
But I completely failed to put it together :/
---- MY SOLUTION
In the end I found something completely different that you guys suggested.
Took me whole day to make it :/
groups :: [Int] -> [Int]
groups list = [sum x | x <- makelist list]
makelist :: [Int] -> [[Int]]
makelist xs = reverse (foldl (\acc x -> zero x acc) [[]] xs)
zero :: Int -> [[Int]] -> [[Int]]
zero x acc | x == 0 = addnewtolist acc
| otherwise = addtolist x acc
addtolist :: Int -> [[Int]] -> [[Int]]
addtolist i listlist = (i : (head listlist)) : (drop 1 listlist)
addnewtolist :: [[Int]] -> [[Int]]
addnewtolist listlist = [] : listlist
I'm going to give you some hints, rather than a complete solution, since this sounds like it may be a homework assignment.
I like the breakdown of steps you've suggested. For the first step (going from a list of numbers with zero markers to a list of lists), I suggest doing an explicit recursion; try this for a template:
splits [] = {- ... -}
splits (0:xs) = {- ... -}
splits (x:xs) = {- ... -}
You can also abuse groupBy if you're careful.
For the second step, it looks like you're almost there; the last step you need is to take a look at the map :: (a -> b) -> ([a] -> [b]) function, which takes a normal function and runs it on each element of a list.
As a bonus exercise, you might want to think about how you might do the whole thing in one shot as a single fold. It's possible -- and even not too difficult, if you track through what the types of the various arguments to foldr/foldl would have to be!
Additions since the question changed:
Since it looks like you've worked out a solution, I now feel comfortable giving some spoilers. =)
I suggested two possible implementations; one that goes step-by-step, as you suggested, and another that goes all at once. The step-by-step one could look like this:
splits [] = []
splits (0:xs) = [] : splits xs
splits (x:xs) = case splits xs of
[] -> [[x]]
(ys:yss) -> ((x:ys):yss)
groups' = map sum . splits
Or like this:
splits' = groupBy (\x y -> y /= 0)
groups'' = map sum . splits'
The all-at-once version might look like this:
accumulate 0 xs = 0:xs
accumulate n (x:xs) = (n+x):xs
groups''' = foldr accumulate [0]
To check that you understand these, here are a few exercises you might like to try:
What do splits and splits' do with [1,2,3,0,4,5]? [1,2,0,3,4,0]? [0]? []? Check your predictions in ghci.
Predict what each of the four versions of groups (including yours) output for inputs like [] or [1,2,0,3,4,0], and then test your prediction in ghci.
Modify groups''' to exhibit the behavior of one of the other implementations.
Modify groups''' to use foldl instead of foldr.
Now that you've completed the problem on your own, I am showing you a slightly less verbose version. Foldr seems better in my opinion to this problem*, but because you asked for foldl I will show you my solution using both functions.
Also, your example appears to be incorrect, the sum of [5,2,1] is 8, not 7.
The foldr version.
makelist' l = foldr (\x (n:ns) -> if x == 0 then 0:(n:ns) else (x + n):ns) [0] l
In this version, we traverse the list, if the current element (x) is a 0, we add a new element to the accumulator list (n:ns). Otherwise, we add the value of the current element to the value of the front element of the accumulator, and replace the front value of the accumulator with this value.
Step by step:
acc = [0], x = 1. Result is [0+1]
acc = [1], x = 2. Result is [1+2]
acc = [3], x = 5. Result is [3+5]
acc = [8], x = 0. Result is 0:[8]
acc = [0,8], x = 4. Result is [0+4,8]
acc = [4,8], x = 3. Result is [4+3,8]
acc = [7,8], x = 0. Result is 0:[7,8]
acc = [0,7,8], x = 3. Result is [0+3,7,8]
acc = [3,7,8], x = 2. Result is [3+2,7,8]
acc = [5,7,8], x = 1. Result is [5+1,7,8] = [6,7,8]
There you have it!
And the foldl version. Works similarly as above, but produces a reversed list, hence the use of reverse at the beginning of this function to unreverse the list.
makelist l = reverse $ foldl (\(n:ns) x -> if x == 0 then 0:(n:ns) else (x + n):ns) [0] l
*Folding the list from the right allows the cons (:) function to be used naturally, using my method with a left fold produces a reversed list. (There is likely a simpler way to do the left fold version that I did not think of that eliminates this triviality.)
As you already solved it, another version:
subListSums list = reverse $ foldl subSum [0] list where
subSum xs 0 = 0 : xs
subSum (x:xs) n = (x+n) : xs
(Assuming that you have only non-negative numbers in the list)
I'm having a problem creating an function similar to the nub function.
I need this func to remove duplicated elements form a list.
An element is duplicated when 2 elements have the same email, and it should keep the newer one (is closer to the end of the list).
type Regist = [name,email,,...,date]
type ListRe = [Regist]
rmDup ListRe -> ListRe
rmDup [] = []
rmDup [a] = [a]
rmDup (h:t) | isDup h (head t) = rmDup t
| otherwise = h : rmDup t
isDup :: Regist -> Regist -> Bool
isDup (a:b:c:xs) (d:e:f:ts) = b==e
The problem is that the function doesn't delete duplicated elements unless they are together in the list.
Just use nubBy, and specify an equality function that compares things the way you want.
And I guess reverse the list a couple of times if you want to keep the last element instead of the first.
Slightly doctored version of your original code to make it run:
type Regist = [String]
type ListRe = [Regist]
rmDup :: ListRe -> ListRe
rmDup [] = []
rmDup (x:xs) = x : rmDup (filter (\y -> not(x == y)) xs)
Result:
*Main> rmDup [["a", "b"], ["a", "d"], ["a", "b"]]
[["a","b"],["a","d"]]
Anon is correct: nubBy is the function you are looking for, and can be found in Data.List.
That said, you want a function rem which accepts a list xs and a function f :: a -> a -> Bool (on which elements are compared for removal from xs). Since the definition is recursive, you need a base case and a recursive case.
In the base case xs = [] and rem f xs = [], since the result of removing all duplicate elements from [] is []:
rem :: Eq a => (a -> a -> Bool) -> [a] -> [a]
rem f [] = []
In the recursive case, xs = (a:as). Let as' be the list obtained by removing all elements a' such that f a a' = True from the list as. This is simply the function filter (\a' -> not $ f a a') applied to the list as. Them rem f (a:as) is the result of recursively calling rem f on as', that is, a : rem f as':
rem f (a:as) = a : rem f $ filter (\a' -> not $ f a a') as
Replace f be a function comparing your list elements for the appropriate equality (e-mail addresses).
While nubBy with two reverse's is probably the best among simple solutions (and probably exactly what Justin needs for his task), one should not forget that it isn't the ideal solution in terms of efficiency - after all nubBy is O(n^2) (in the "worst case" - when there are no duplicates). Two reverse's will also take their toll (in the form of memory allocation).
For more efficient implementation Data.Map (O(logN) on inserts) can be used as an intermediate "latest non duplicating element" holder (Set.insert replaces older element with newer if there is a collision):
import Data.List
import Data.Function
import qualified Data.Set as S
newtype Regis i e = Regis { toTuple :: (i,[e]) }
selector (Regis (_,(_:a:_))) = a
instance Eq e => Eq (Regis i e) where
(==) = (==) `on` selector
instance Ord e => Ord (Regis i e) where
compare = compare `on` selector
rmSet xs = map snd . sortBy (compare `on` fst) . map toTuple . S.toList $ set
where
set = foldl' (flip (S.insert . Regis)) S.empty (zip [1..] xs)
While nubBy implementation is definitely much simpler:
rmNub xs = reverse . nubBy ((==) `on` (!!1)) . reverse $ xs
on 10M elements list (with lots of duplication - nub should play nice here) there is 3 times difference in terms of running time and 700 times difference in memory usage. Compiled with GHC with -O2 :
input = take 10000000 $ map (take 10) $ permutations [1..]
test1 = rmNub input
test2 = rmSet input
Not sure about the nature of the author's data though (the real data might change the picture).
(Assuming you want to figure out an answer, not just call a library function that does this job for you.)
You get what you ask for. What if h is not equal to head t but is instead equal to the 3rd element of t? You need to write an algorithm that compares h with every element of t, not just the first element.
Why not putting everything in a Map from email to Regist (of course respecting your "keep the newest" rule), and then transform the values of the map back in the list? That's the most efficient way I can think of.
I used Alexei Polkhanov's answer and came to the following, so you can remove duplicates from lists with a type that extends Eq class.
removeDuplicates :: Eq a => [[a]] -> [[a]]
removeDuplicates [] = []
removeDuplicates (x:xs) = x : removeDuplicates (filter (\y -> not (x == y)) xs)
Examples:
*Verdieping> removeDuplicates [[1],[2],[1],[1,2],[1,2]]
[[1],[2],[1,2]]
*Verdieping> removeDuplicates [["a","b"],["a"],["a","b"],["c"],["c"]]
[["a","b"],["a"],["c"]]