Map function at Haskell - haskell

The question : Define the function setElements, which takes a list indxs of pairs of (n, x) (where n is an
Int), and a list xs, and for each pair (n, x) it sets the n’th element in xs to be x.
If a pair contains in its first component a negative index, or an index larger than the
length of xs, ignore this pair.
If the indxs list contains more than one pair with the same key (e.g., [(1,'a'),(1,'b')]), the
last occurrence of the key will be the one that holds.
Examples:
setElements [(1, 'a'), (-4, 't'), (3, 'b')] "#####" = "#a#b#"
setElements [(2, 50), (50, 2)] [8, 7, 6, 5, 4] = [8, 7, 50, 5, 4]
setElements [(3, 'a'),(5, 'b'),(3, 'c')] "wwwwwww" = "wwwcwbw"
my code:
--1.a
setElement:: Int -> a -> [a] -> [a]
setElement n x xs = (take n xs ++ x:tail(drop n xs))
--b
setElements :: [(Int,b)] -> [b] -> [b]
setElements (x:xs) = map (setElement (fst x) (snd x) [b])

The setElement function is almost right, but the standard way of doing it is.
take n xs ++ [x] ++ drop (n + 1) xs
But again this is not taking care of negative n. This can be easilt done using pattern mathing.
setElement n x xs | n < 0 = xs
| otherwise = take n xs ++ [x] ++ drop (n + 1) xs
For setElements you will have to think recursively. The function should simply return the second argument when first argument is empty.
setElements [] ys = ys
When the first list is not empty
take the first pair and manipulate the second argument
the result of the above should be send recursively to rest of the first argument
setElements ((x,b):xs) ys = let ps = ...
in setElements ....
Fill in the blanks. Its very simple actually.

Related

Return a list, which contains a pair of elements, but only if the respective elements' sums are odd

Implement the oddPairs :: [Int] -> [Int] -> [(Int, Int)] function that returns a list of pairs, but only if the parameters' lists' respective elements' sums are odd.
For example:
oddPairs [1,2,3] [2,2,2] == [(1,2),(3,2)]
oddPairs [1,3,5] [2,4,6] == zip [1,3,5] [2,4,6]
oddPairs [1,2,3] [1,2,3] == []
So far, I've tried
oddPairs (x:xs) (y:ys) | (x+y) `mod` 2 == 0 = []
| (x+y) `mod` 2 /= 0 = [(x, y)] ++ oddPairs (xs) (ys)
And on the first example, it returns only [(1,2)], on the second, it returns the correct values but with a Non-exhaustive patterns error.
In case the two items are even, you should not just return an empty list, but continue the recursion until at least one of the lists is exhausted, so:
oddPairs :: Integral a => [a] -> [a] -> [(a, a)]
oddPairs [] _ = []
oddPairs _ [] = []
oddPairs (x:xs) (y:ys)
-- keep searching for new items &downarrow;
| (x+y) `mod` 2 == 0 = oddPairs xs ys
| otherwise = (x, y) : oddPairs xs ys
Another way to look at the problem is that you want only the pairs that have an odd sum. This is a slight difference in emphasis that might lead to the following.
Use the zip function to combine each list into pairs. Then use filter to find the ones with odd sum.
oddPairs :: Integral a => [a] -> [a] -> [(a, a)]
oddPairs f s = filter oddPair (zip f s)
where oddPair (l, r) = not $ even (l + r)
Quite straightforwardly with a list comprehension:
oddPairs :: [Int] -> [Int] -> [(Int, Int)]
oddPairs ms ns = [(m, n) | (m, n) <- zip ms ns, odd (m + n)]
Indeed:
> oddPairs [1, 2, 3] [2, 2, 2] == [(1, 2),(3, 2)]
True
> oddPairs [1, 3, 5] [2, 4, 6] == zip [1, 3, 5] [2, 4, 6]
True
> oddPairs [1, 2, 3] [1, 2, 3] == []
True

Removing tuples that have the same pair of values from a list

I want to remove all the tuples that have the same pair of values, e.g. [(1,1), (2,3), (2,2), (3,4)] I want [(2, 3), (3, 4)]. I am working in Haskell. This is what I tried:
unique [] = []
unique (x:xs) = if (fst x) == (snd x) then unique (xs) else x:[]
And the output was:
[(2,3)]
I am confused on why (3, 4) did not appear.
Because your else case says:
unique [] = []
unique (x:xs) = if (fst x) == (snd x) then unique (xs) else x:[]
It thus says if fst x is not equal to snd x, then we return x : [] (or shorter [x]), and we are done. So it does not perform recursion on the rest of the list.
We can solve this by adding recursion on the rest of the list, like:
unique [] = []
unique (x:xs) = if fst x == snd x then unique xs else x : unique xs
That being said, we can use a filter here, like:
unique :: Eq a => [(a, a)] -> [(a, a)]
unique = filter (\(x, y) -> x /= y)
or even shorter:
unique :: Eq a => [(a, a)] -> [(a, a)]
unique = filter (uncurry (/=))
We thus retain all elements for which the first element x is not equal to the second element y.

Understanding the work of foldr and unfoldr

I have hard time understanding how these bits of code work.
"Map" function must apply the function to all elements in given list, and generate list consist of results of applying. So we are giving our function f and some list, then in lambda expression our list transforms into head "x" and tail "xs", we applying function "f" to x and append it to "xs". But what happens next? How and what exactly foldr takes for its second argument (which must be some starting value usually). And for what purpose empty list?
And function "rangeTo" : we are creating lambda expression, where we are checking that we are over the end of range, end if we are than we are giving Nothing, or if we are not at end, we are giving pair where first number append to resulting list, and second number used as next value for "from". Is it all what happens in this function, or I'm missing something?
--custom map function through foldr
map :: (a -> b) -> [a] -> [b]
map f = foldr (\x xs -> f x : xs) []
--function to create list with numbers from first argument till second and step "step"
rangeTo :: Integer -> Integer -> Integer -> [Integer]
rangeTo from to step = unfoldr (\from -> if from >= to then Nothing else Just (from, from+step)) from
To understand How foldr operates on a list. It is better to write down the definition of foldr as
foldr step z xs
= x1 `step` foldr step z xs1 -- where xs = x:xs1
= x1 `step` (x2 `step` foldr step z xs2) -- where xs = x1:x2:xs2
= x1 `step` (x2 `step` ... (xn `step` foldr step z [])...) -- where xs = x1:x2...xn:[]
and
foldr step z [] = z
For your case:
foldr (\x xs -> f x : xs) []
where
step = (\x xs -> f x : xs)
z = []
From the definition of foldr, the innermost expression
(xn `step` foldr step z [])
is evaluated first, that is
xn `step` foldr step z []
= step xn (foldr step z [])
= step xn z
= step xn [] -- z = []
= f xn : [] -- step = (\x xs -> f x : xs)
= [f xn]
what happens next? The evaluation going on as
x(n-1) `step` (xn `step` foldr step z [])
= step x(n-1) [f xn]
= f x(n-1) : [f xn]
= [f x(n-1), f xn]
untill:
x1 `step` (x2 ...
= step x1 [f x2, ..., f xn]
= [f x1, f x2, ... f xn]
So we are giving our function f and some list, then in lambda expression our list transforms into head "x" and tail "xs", we applying function "f" to x and append it to "xs".
This is not the case. Look closely at the implementation:
map :: (a -> b) -> [a] -> [b]
map f = foldr (\x xs -> f x : xs) []
There is an implied variable here, we can add it back in:
map :: (a -> b) -> [a] -> [b]
map f ls = foldr (\x xs -> f x : xs) [] ls
map takes two arguments, a function f and a list ls. It passes ls to foldr as the list to fold over, and it passes [] as the starting accumulator value. The lambda takes a list element x and an accumulator xs (initially []), and returns a new accumulator f x : xs. It does not perform a head or tail anywhere; x and xs were never part of the same list.
Let's step through the evaluation to see how this function works:
map (1+) [2, 4, 8]
foldr (\x xs -> (1+) x : xs) [] [2, 4, 8] -- x = 8, xs = []
foldr (\x xs -> (1+) x : xs) [9] [2, 4] -- x = 4, xs = [9]
foldr (\x xs -> (1+) x : xs) [5, 9] [2] -- x = 2, xs = [5, 9]
foldr (\x xs -> (1+) x : xs) [3, 5, 9] [] -- xs = [3, 5, 9]
map (1+) [2, 4, 8] == [3, 5, 9]
The empty list accumulates values passed through f, starting from the right end of the input list.
And function "rangeTo" : we are creating lambda expression, where we are checking that we are over the end of range, end if we are than we are giving Nothing, or if we are not at end, we are giving pair where first number append to resulting list, and second number used as next value for "from". Is it all what happens in this function, or I'm missing something?
Yes, that's exactly what's going on. The lambda takes an accumulator, and returns the next value to put in the list and a new accumulator, or Nothing if the list should end. The accumulator in this case is the current value in the list. The list should end if that value is past the end of the range. Otherwise it calculates the next accumulator by adding the step.
Again, we can step through the evaluation:
rangeTo 3 11 2 -- from = 3, to = 11, step = 2
Just (3, 5) -- from = 3
Just (5, 7) -- from = 3 + step = 5
Just (7, 9) -- from = 5 + step = 7
Just (9, 11) -- from = 7 + step = 9
Nothing -- from = 9 + step = 11, 11 >= to
rangeTo 3 11 2 == [3, 5, 7, 9]

Haskell List Comprehension and Pattern Matching

I'm looking for a function which gives me all matching numbers of a letter, for example giveNumber "D" [("D", 5), ("A", 4) ("D", 25)] = [5,25]
giveNumber :: String -> [(String, a)] -> [a]
giveNumber letter (x:xs) = [snd x | x <- xs | fst x == letter]
I get a parser error with that.
You don't need pattern matching or list comprehensions, since I'd say this is easier with filter and map:
giveNumber :: (Eq a) => [(a, b)] -> [b]
giveNumber x ys = map snd $ filter ((== x) . fst) ys
Although you could do it with some minor adjustments to your code:
giveNumber letter xs = [snd x | x <- xs, fst x == letter]
This may make more sense to you, but either will be about the same in execution time. What you were doing wrong was that you had a second | symbol in your comprehension where you needed a comma, and you didn't need to pattern match (x:xs) as an argument, since the x <- xs loops over all the xs.
Alternatively, you could do it even more simply as
giveNumber letter xs = [y | (x, y) <- xs, x == letter]
Of the three choices, this one is probably the most readable and easiest to understand, but I like the first one best because it's all from composing higher order functions and can be eta reduced to
giveNumber x = map snd . filter ((== x) . fst))
making the ys parameter implicit.
You may also be interested in the lookup function that is built in:
lookup :: Eq a => a -> [(a, b)] -> Maybe b
but this only looks up a single element, with the possibility for failure.
You have 2 little mistakes:
1) You miss a coma in [("D", 5), ("A", 4) , ("D", 25)]
2) in list comprehension you used | twice, not once
giveNumber letter xs = [snd x | x <- xs , fst x == letter]
You could write a bit prettier:
giveNumber letter xs = [y | (x,y) <- xs , x == letter]
By the way, this function is more general then String -> [(String, a)] -> [a] :
giveNumber :: Eq a => a -> [(a, t)] -> [t]

Nested loop equivalent

I want to do a list of concatenations in Haskell.
I have [1,2,3] and [4,5,6]
and i want to produce [14,15,16,24,25,26,34,35,36].
I know I can use zipWith or sth, but how to do equivalent of:
foreach in first_array
foreach in second_array
I guess I have to use map and half curried functions, but can't really make it alone :S
You could use list comprehension to do it:
[x * 10 + y | x <- [1..3], y <- [4..6]]
In fact this is a direct translation of a nested loop, since the first one is the outer / slower index, and the second one is the faster / inner index.
You can exploit the fact that lists are monads and use the do notation:
do
a <- [1, 2, 3]
b <- [4, 5, 6]
return $ a * 10 + b
You can also exploit the fact that lists are applicative functors (assuming you have Control.Applicative imported):
(+) <$> (*10) <$> [1,2,3] <*> [4,5,6]
Both result in the following:
[14,15,16,24,25,26,34,35,36]
If you really like seeing for in your code you can also do something like this:
for :: [a] -> (a -> b) -> [b]
for = flip map
nested :: [Integer]
nested = concat nested_list
where nested_list =
for [1, 2, 3] (\i ->
for [4, 5, 6] (\j ->
i * 10 + j
)
)
You could also look into for and Identity for a more idiomatic approach.
Nested loops correspond to nested uses of map or similar functions. First approximation:
notThereYet :: [[Integer]]
notThereYet = map (\x -> map (\y -> x*10 + y) [4, 5, 6]) [1, 2, 3]
That gives you nested lists, which you can eliminate in two ways. One is to use the concat :: [[a]] -> [a] function:
solution1 :: [Integer]
solution1 = concat (map (\x -> map (\y -> x*10 + y) [4, 5, 6]) [1, 2, 3])
Another is to use this built-in function:
concatMap :: (a -> [b]) -> [a] -> [b]
concatMap f xs = concat (map f xs)
Using that:
solution2 :: [Integer]
solution2 = concatMap (\x -> map (\y -> x*10 + y) [4, 5, 6]) [1, 2, 3]
Other people have mentioned list comprehensions and the list monad, but those really bottom down to nested uses of concatMap.
Because do notation and the list comprehension have been said already. The only other option I know is via the liftM2 combinator from Control.Monad. Which is the exact same thing as the previous two.
liftM2 (\a b -> a * 10 + b) [1..3] [4..6]
The general solution of the concatenation of two lists of integers is this:
concatInt [] xs = xs
concatInt xs [] = xs
concatInt xs ys = [join x y | x <- xs , y <- ys ]
where
join x y = firstPart + secondPart
where
firstPart = x * 10 ^ lengthSecondPart
lengthSecondPart = 1 + (truncate $ logBase 10 (fromIntegral y))
secondPart = y
Example: concatInt [1,2,3] [4,5,6] == [14,15,16,24,25,26,34,35,36]
More complex example:
concatInt [0,2,10,1,100,200] [24,2,999,44,3] == [24,2,999,44,3,224,22,2999,244,23,1024,102,10999,1044,103,124,12,1999,144,13,10024,1002,100999,10044,1003,20024,2002,200999,20044,2003]

Resources