What is the purpose of the y parameter in this code? - haskell

This Haskell code prints out [0,10,20,30,40,50] but I don't understand what the y is suppose to do in the third line.
f [] = []
f [x] = [x]
f (x:y:xs) = x : f xs
main = print (f [0,5..50])
Why doesn't it print the same result if I say f (x:xs) = x : f xs instead?

(x:y:xy) is matching a list with at least two elements and binding x to the first element, y to the second and xs to the tail of the list.
By calling x: f xs the second element is removed from the resulting list.
As this value is never used, it doesn't need to be called y at all.
f [] = []
f [x] = [x]
f (x:_:xs) = x : f xs
main = print (f [0,5..50])
If you had instead written:
f [] = []
f [x] = [x]
f (x:xs) = x : f xs
main = print (f [0,5..50])
The result would just be the original list, as that second element is never "dropped."

The pattern in f (x:y:xs) is saying: get the input to the function, assign the first element of the list to x, the second to y and the rest (tail) of the list to xs. And this function is returning the first element x followed by the result of applying f to xs. In essence, you are removing every second element from the list.

Related

Why is it sometimes possible to fold an infinite list from the right?

I have been going through the excellent CIS 194 course when I got stuck on Part 5 of Homework 6. It revolves around implementing the ruler function without any divisibility testing.
I found that it is possible to build the ruler function by continuously interspersing an accumulator with values from an infinite list.
nats = [0,1,2,3,..]
[3]
[2,3,2]
[1,2,1,3,1,2,1]
[0,1,0,2,0,1,0,3,0,1,0,2,0]
Then I tried implementing this algorithm for Stream datatype which is a list without nil
data Stream a = Cons a (Stream a)
streamToList :: Stream a -> [a]
streamToList (Cons x xs) = x : streamToList xs
instance Show a => Show (Stream a) where
show = show . take 20 . streamToList
streamFromSeed :: (a -> a) -> a -> Stream a
streamFromSeed f x = Cons x (streamFromSeed f (f x))
nats :: Stream Integer
nats = streamFromSeed succ 0
interleave x (Cons y ys) = Cons x (Cons y (interleave x ys))
foldStream f (Cons x xs) = f x (foldStream f xs)
ruler = foldStream interleave nats
As expected, I got stackoverflow error since I was trying to fold from the right. However, I was surprised to see the same algorithm work for normal infinite lists.
import Data.List
interleave x list = [x] ++ (intersperse x list) ++ [x]
ruler = take 20 (foldr interleave [] [0..])
What am I missing? Why one implementation works while the other doesn't?
Your interleave is insufficiently lazy. The magic thing that right folds must do to work on infinite structures is to not inspect the result of the folded value too closely before they do the first bit of computation. So:
interleave x stream = Cons x $ case stream of
Cons y ys -> Cons y (interleave x ys)
This produces Cons x _ before inspecting stream; in contrast, your version requires stream to be evaluated a bit before it can pass to the right hand side of the equation, which essentially forces the entire fold to happen before any constructor gets produced.
You can also see this in your list version of interleave:
interleave x list = [x] ++ intersperse x list ++ [x]
The first element of the returned list (x) is known before intersperse starts pattern matching on list.
We can inspect the source code of foldr [src]. A less noisy version looks like:
foldr f z [] = z
foldr f z (x:xs) = f x (foldr f z xs)
Haskell does not evaluate eagerly. This thus means that, unless you need (foldr f z xs), it will not evaluate the accumulator. This thus means that f does not need the second parameter, for example because the first item x has a certain value, it will not evaluate the accumulator.
For example if we implement takeWhileNeq:
takeWhileNeq a = foldr f []
where f x xs -> if x == a then [] else (x:xs)
if we thus run this on a list takeWhileNeq 2 [1,4,2,5], then it will not evaluate anything. If we however want to print the result it will evaluate this as:
f 1 (foldr f [4,2,5])
and f will inspect if 1 == 2, since that is not the case, it will return (x:xs), so:
-> 1 : foldr f [4,2,5]
so now it will evaluate 4 == 2, and because this is false, it will evaluate this to:
-> 1 : (4 : foldr f [2,5])
now we evaluate 2 == 2, and since this is True, the function returns the empty list, and ingores the accumulator, so it will never look at foldr f [5]:
-> 1 : (4 : [])
For an infinite list, it will thus also result an empty list and ignore folding the rest of the list.

How to define a correct edge definition for this recursive function?

Solution if anyone is interested:
f :: Ord a => [a] -> [a]
f [] = []
f [x] = []
f (x:y:xs)
| x < y = max x y : f (y:xs)
| otherwise = f (y:xs)
sample input:
f [1,3,2,4,3,4,5] == [3,4,4,5]
f [5,10,6,11,7,12] == [10,11,12]
Updated code:
f [] = []
f [x] = [x]
f (x:y:xs)
| x < y = max x y : f (y:xs)
| otherwise = f (y:xs)
The problem is that it outputs the last number twice:
f [5,10,6,11,7,12] == [10,11,12,12]
Old content below
I am writing a function that takes a list and returns the elements that are larger than the previous one. I came up with this, but the problem is that when it reaches the last element, xs !! 0 doesn't exist, thus the error. How can I define a correct exit point in this case?
my code:
f :: Ord a => [a] -> [a]
f [] = []
f (x:xs) = max x (xs !! 0) : f xs
error:
[3,3,4,4,4,5,*** Exception: Prelude.!!: index too large
You aren't always going to add a new element to the result; sometimes you'll add nothing.
f :: Ord a => [a] -> [a]
f [] = []
f [x] = [x]
f (x:y:xs) = _ -- what goes here?
For your recursive case, there are two possibilities:
If x < y, you'll add y to the result.
Otherwise, you won't add y to the result. In fact, you won't add anything.
In either case, you need to include y in the recursive call, not just xs, so that on the next iteration, y will be the first element to be compared to the one after it.
I leave it as an exercise to implement the above logic as your recursive case.

Haskell strange (to me) behavior

I am working on 99 problems of Haskell (https://wiki.haskell.org/99_questions/1_to_10)
, I have a question regarding to problem # 8.
8 Problem 8
(**) Eliminate consecutive duplicates of list elements.
If a list contains repeated elements they should be replaced with a single copy of the element. The order of the elements should not be changed.
I've solved this problem with foldr function successfully.
compress :: Eq e => [e] -> [e]
compress = let f v [] = [v]
f v acc
| head acc == v = acc
| otherwise = v:acc
in foldr f []
But when I try to solve the same problem with recursion like this:
compress' :: Eq e => [e] -> [e]
compress' = let f acc [] = acc
f [] (x:xs) = f [x] xs
f acc (x:xs) | x == last acc = acc ++ f acc xs
| otherwise = f (acc ++ [x]) xs
in f []
I see really strange behavior. I see this result of this function:
compress' "aaaabccaadeeee"
"aaaabcabcaabcadeabcadeabcadeabcade"
But if I add break point at line
compress' = let f acc [] = acc
it gives me correct result:
ghci> compress' "aaaabccaadeeee"
"aaaabcabcaabcadeabcadeabcadeabcade"
ghci> :break 304
Breakpoint 7 activated at haskell-tut.hs:304:28-30
ghci> compress' "aaaabccaadeeee"
"aaaabcabcaabcadeabcadeabcadeStopped in Main.compress'.f, haskell-tut.hs:304:28-30
_result :: [Char] = _
acc :: [Char] = "abcade"
[haskell-tut.hs:304:28-30] ghci> :con
abcade"
ghci>
I feel like it is some thing about Haskell laziness.... It is my best assumption.
Can any one explain why do I get this odd result during execution and correct result during execution with breakpoint?
The problem comes from the expression below:
x == last acc = acc ++ f acc xs
It doesn't need to append the acc string at the beginning of the result, so the correction should be:
x == last acc = f acc xs
Note that acc contains the correct result you want, i.e. the string without consecutive duplicates, hence you can see the correct result acc :: [Char] = "abcade" at the break point when the input list is []. But when it returns, it combines the previous result as acc ++ "abcade", from which the "abcade" at the end of "aaaabcabcaabcadeabcadeabcadeabcade"

How to apply a function to a specific element of a list

How can I apply a function to only a single element of a list?
Any suggestion?
Example:
let list = [1,2,3,4,3,6]
function x = x * 2
in ...
I want to apply function only to the first occurance of 3 and stop there.
Output:
List = [1,2,6,4,3,6] -- [1, 2, function 3, 4, 3, 6]
To map or not to map, that is the question.
Better not to map.
Why? Because map id == id anyway, and you only want to map through one element, the first one found to be equal to the argument given.
Thus, split the list in two, change the found element, and glue them all back together. Simple.
See: span :: (a -> Bool) -> [a] -> ([a], [a]).
Write: revappend (xs :: [a]) (ys :: [a]) == append (reverse xs) ys, only efficient.
Or fuse all the pieces together into one function. You can code it directly with manual recursion, or using foldr. Remember,
map f xs = foldr (\x r -> f x : r) [] xs
takeWhile p xs = foldr (\x r -> if p x then x : r else []) [] xs
takeUntil p xs = foldr (\x r -> if p x then [x] else x : r) [] xs
filter p xs = foldr (\x r -> if p x then x : r else r) [] xs
duplicate xs = foldr (\x r -> x : x : r) [] xs
mapFirstThat p f xs = -- ... your function
etc. Although, foldr won't be a direct fit, as you need the combining function of the (\x xs r -> ...) variety. That is known as paramorphism, and can be faked by feeding tails xs to the foldr, instead.
you need to maintain some type of state to indicate the first instance of the value, since map will apply the function to all values.
Perhaps something like this
map (\(b,x) -> if (b) then f x else x) $ markFirst 3 [1,2,3,4,3,6]
and
markFirst :: a -> [a] -> [(Boolean,a)]
markFirst a [] = []
markFirst a (x:xs) | x==a = (True,x): zip (repeat False) xs
| otherwise = (False,x): markFirst a xs
I'm sure there is an easier way, but that's the best I came up with at this time on the day before Thanksgiving.
Here is another approach based on the comment below
> let leftap f (x,y) = f x ++ y
leftap (map (\x -> if(x==3) then f x else x)) $ splitAt 3 [1,2,3,4,3,6]
You can just create a simple function which multiples a number by two:
times_two :: (Num a) => a -> a
times_two x = x * 2
Then simply search for the specified element in the list, and apply times_two to it. Something like this could work:
map_one_element :: (Eq a, Num a) => a -> (a -> a) -> [a] -> [a]
-- base case
map_one_element _ _ [] = []
-- recursive case
map_one_element x f (y:ys)
-- ff element is found, apply f to it and add rest of the list normally
| x == y = f y : ys
-- first occurence hasnt been found, keep recursing
| otherwise = y : map_one_element x f ys
Which works as follows:
*Main> map_one_element 3 times_two [1,2,3,4,3,6]
[1,2,6,4,3,6]

Haskell - format issue

i am a beginner in haskell programming and very often i get the error
xxx.hs:30:1: parse error on input `xxx'
And often there is a little bit playing with the format the solution. Its the same code and it looks the same, but after playing around, the error is gone.
At the moment I've got the error
LookupAll.hs:30:1: parse error on input `lookupAll'
After that code:
lookupOne :: Int -> [(Int,a)] -> [a]
lookupOne _ [] = []
lookupOne x list =
if fst(head list) == x then snd(head list) : []
lookupOne x (tail list)
-- | Given a list of keys and a list of pairs of key and value
-- 'lookupAll' looks up the list of associated values for each key
-- and concatenates the results.
lookupAll :: [Int] -> [(Int,a)] -> [a]
lookupAll [] _ = []
lookupAll _ [] = []
lookupAll xs list = lookupOne h list ++ lookupAll t list
where
h = head xs
t = tail xs
But I have done everything right in my opinion. There are no tabs or something like that. Always 4 spaces. Is there a general solutoin for this problems? I am using notepad++ at the moment.
Thanks!
The problem is not with lookupAll, it's actually with the previous two lines of code
if fst (head list) == x then snd (head list) : []
lookupOne x (tail list)
You haven't included an else on this if statement. My guess is that you meant
if fst (head list) == x then snd (head list) : []
else lookupOne x (tail list)
Which I personally would prefer to format as
if fst (head list) == x
then snd (head list) : []
else lookupOne x (tail list)
but that's a matter of taste.
If you are wanting to accumulate a list of values that match a condition, there are a few ways. By far the easiest is to use filter, but you can also use explicit recursion. To use filter, you could write your function as
lookupOne x list
= map snd -- Return only the values from the assoc list
$ filter (\y -> fst y == x) list -- Find each pair whose first element equals x
If you wanted to use recursion, you could instead write it as
lookupOne _ [] = [] -- The base case pattern
lookupOne x (y:ys) = -- Pattern match with (:), don't have to use head and tail
if fst y == x -- Check if the key and lookup value match
then snd y : lookupOne x ys -- If so, prepend it onto the result of looking up the rest of the list
else lookupOne x ys -- Otherwise, just return the result of looking up the rest of the list
Both of these are equivalent. In fact, you can implement filter as
filter cond [] = []
filter cond (x:xs) =
if cond x
then x : filter cond xs
else filter cond xs
And map as
map f [] = []
map f (x:xs) = f x : map f xs
Hopefully you can spot the similarities between filter and lookupOne, and with map consider f == snd, so you have a merger of the two patterns of map and filter in the explicit recursive version of lookupOne. You could generalize this combined pattern into a higher order function
mapFilter :: (a -> b) -> (a -> Bool) -> [a] -> [b]
mapFilter f cond [] = []
mapFilter f cond (x:xs) =
if cond x
then f x : mapFilter f cond xs
else : mapFilter f cond xs
Which you can use to implement lookupOne as
lookupOne x list = mapFilter snd (\y -> fst y == x) list
Or more simply
lookupOne x = mapFilter snd ((== x) . fst)
I think #bheklilr is right - you're missing an else.
You could fix this particular formatting problem, however, by forming lookupOne as a function composition, rather than writing your own new recursive function.
For example, you can get the right kind of behaviour by defining lookupOne like this:
lookupOne a = map snd . filter ((==) a . fst)
This way it's clearer that you're first filtering out the elements of the input list for which the first element of the tuple matches the key, and then extracting just the second element of each tuple.

Resources