I have the following function and should write it with foldr.
f [] = []
f (x:xs)
| x == 0 = case f xs of
[] -> []
ys#(y:_) -> if y == 0 then ys else x : ys
| otherwise = x : f xs
This function basically removes all trailing 0's, but keeps at most one leading 0.
For example:
f [1,2,0,0] = [1,2]
f [1,2,0,1] = [1,2,0,1]
f [0,0,1,0,0,3] = [0,1,0,3]
I have foldr op z lst, but don't know what op can be. z should be [].
Example I traced:
foldr op [] [0,0,1,0,0,3]
-> 0 op (0 op (1 op (0 op (0 op (3 op []))))
|-- [3] ---|
|---[0,3] ------|
|-----[0,3]-----------|
|-----[1,0,3]---------------|
|-----[0,1,0,3]-------------------|
|-----[0,1,0,3]-------------------------|
How about
f = fst . foldr (\ x (xs', y) -> if y && x == 0 then (xs', x==0) else (x:xs', x==0 )) ([], True)
in this case, op returns a tuple of list and Bool, Bool is for tracking whether the accumulated list started with 0. At the end, we use fst to discard the Bool. We have to use ([], True) as the initial value, to handle the trailing zero case.
Related
I'm trying to write a program that takes in two lists and a binary operation and takes each element of one list and applies it to the other using the binary operation. I have it working but not sure how to change it so it works with any binary operator. Here's examples :
myFunction (+) [100,200,300] [4,3,2,1] would return
[96,97,98,99,196,197,198,199,296,297,298,299]
myFunction (+) [100,200,300] [4,3,2,1] would return
[96,97,98,99,196,197,198,199,296,297,298,299]
This is what I have working with specific binary operations
oneEle :: Char -> Integer -> [Integer] -> [Integer]
oneEle a x [] = []
oneEle a x y
| (a == '+') = [p + x | p <- y]
| (a == '-') = [p - x | p <- y]
| (a == '*') = [p * x | p <- y]
| (a == ':') = [p * x | p <- y]
myFunction :: Char -> [Integer] -> [Integer] -> [Integer]
myFunction a [] [] = []
myFunction a [] y = []
myFunction a x [] = []
myFunction a (x:xs) (y:ys) = oneEle a x ([y] ++ ys) ++ myFunction a xs ([y]++ys)
The simplest way is a list comprehension:
myFunction f xs ys = [f x y | x <- xs, y <- ys]
It may not even be worth defining a new function; instead, just inline that content to the call site.
This function is also available from the standard library by the names liftM2 and liftA2.
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.
I would like to count the number of positive integers/elements in the list. This returns the elements with positive values, how can I count the elements? would like to construct something like count(array(...)).
I would like to see a version with i++ and foldl. That would be very helpful.
countPositivesRec :: [Int] -> [Int]
countPositivesRec [] = []
countPositivesRec (x:xs) | x >= 0 = x : tl
| otherwise = tl
where tl = countPositivesRec xs
Here's a hint: follow the same recursion scheme as before, but return an int at every step.
countPositivesRec :: [Int] -> Int
---
countPositivesRec [] = 0 -- no positives in the empty list
countPositivesRec (x:xs) | x >= 0 = ??
| otherwise = ??
where tl = countPositivesRec xs
One you solve this, it can be rewritten using foldr, if you want.
If you really want to use foldl instead, I would suggest you start by defining a function f such that
f (f (f 0 x0) x1) x2
evaluates to the number of positives in x0,x1,x2. Then you can use foldl f 0 inputList
The function you've written is filter (>=0). As Paul pointed out, the only step remaining is to count and length does that. We can transform the function step by step:
countPositivesRec :: [Int] -> [Int]
countPositivesRec [] = []
countPositivesRec (x:xs) | x >= 0 = x : tl
| otherwise = tl
where tl = countPositivesRec xs
Observe that xs is only used in the transformed form tl. That's what makes this a right fold.
onlypos1 = foldr maybekeep []
where maybekeep x tl | x >= 0 = x : tl
| otherwise = tl
This operation is known as a filter, keeping only some parts:
onlypos2 = filter dowekeep
where dowekeep x = x >= 0
onlypos3 = filter (\x -> x >= 0)
onlypos4 = filter (>= 0)
But this is of course only one of many possible approaches. For instance, strictness analysis can lead to the conclusion that length is better implemented as foldl' (\a _ -> succ a) 0 than foldr (\_ a -> succ a) 0. Indeed, that is its basic form in the Prelude:
length = foldl' (\c _ -> c+1) 0
We see that the combining function of length ignores the value of one argument, merely requires it to be there. This can naturally be merged with our condition that only some elements count:
lengthFilter1 = length . filter
lengthFilter2 pred = foldl' predCount 0
where predCount c x = if pred x then c+1 else c
countNonNegative = lengthFilter2 nonNegative
where nonNegative x = x >= 0
Incidentally, 0 isn't positive. It's non-negative.
In the end, Haskell's lazy lists mean we can use them to fuse traversals; length . filter (>=0) will only read the input list once, because the only reason it's processing results from filter is that length consumes them. The filtered list never exists as a fully expanded structure, unlike e.g. Python or PHP. This form is likely one of the most readable, but others exist, e.g.:
countNonNegatives xs = sum [1 | x <- xs, x >= 0]
You have
filtering p cons x r = if | p x -> cons x r | otherwise -> r
countPositives = length
. filter (> 0)
= foldr (\x r -> r + 1) 0 -- r++
. foldr (filtering (> 0) (:) ) []
= foldr (filtering (> 0) (\x r -> r + 1)) 0
(since folds fuse by composing their reducer transformers, a-la "fold replaces the cons with a reducer operation, so why create the cons in the first place if it gonna be replaced anyway"), and
filtering (> 0) (\x r -> r + 1) x r
= if | (> 0) x -> (\x r -> r + 1) x r | otherwise -> r
= if | x > 0 -> r + 1 | otherwise -> r
and thus, a version with fold and increment that you wanted,
countPositives = foldr (\x r -> if | x > 0 -> r + 1 | otherwise -> r) 0 -- r++
You can take it from here.
plz watch my code
insert x [] = [x]
insert x (y:ys)
| x < y = x:y:ys
| x == y = y:ys ++ [x]
| otherwise = y:insert x ys
insert_sort [] = []
insert_sort (x:xs) = insert x (insert_sort xs)
insert_pair (x,y) [] = [(x,y)]
insert_pair (x,y) ((a,b):yd)
| x > a = (a,b):insert_pair (x,y) yd
| otherwise = (x,y):(a,b):yd
insert_sort_pair [] = []
insert_sort_pair (x:xs) = insert_pair x (insert_sort_pair xs)
insert_high f [] = []
insert_high f (x:y:ys)
| f x y = x:y:ys
| otherwise = y:insert x ys
insert_high f ((a,b):(c,d):yd)
| f a c = (a,b):insert_pair (c,d) yd
| otherwise = (a,b):(c,d):yd
insert_sort_high f [] = []
insert_sort_high f (x:xs) = insert_high (f) x (insert_sort_high (f) xs)
I want to make insert_sort-high can do both insert_sort and insert_pair_sort.
"insert_sort_pair" compare the number in (number,symbol).
For example:
insert_sort_high (<) [3,5,2,1,4] -> [1,2,3,4,5]
insert_sort_high (>) [(2,'a'),(3,'b'),(1,'c')] -> [(1,'c'),(2,'a'),(3,'b')]
But, it doesn't work... how can i fix it?
First, a fundamental misunderstanding.
Write a type for insert_high - it should probably be (a -> a -> Bool) -> [a] -> [a]. But you've written a specialization for lists of tuples, so you've forced it to be less general than that.
You can only cover the general case. You're being misled by your examples.
I'd argue what you really want is
λ insert_sort_high (<) [3,5,2,1,4]
[1,2,3,4,5]
λ insert_sort_high (\(x,y) (a,b) -> x < a) [(2,'a'), (3,'b'), (1,'c')]
[(1,'c'),(2,'a'),(3,'b')]
The latter can be written a little more easily as
λ :m +Data.Function
λ insert_sort_high ((<) `on` fst) [(2,'a'), (3,'b'), (1,'c')]
[(1,'c'),(2,'a'),(3,'b')]
Of course, that's only if you only want sorting to be on the first element of the pair.
λ insert_sort_high ((<) `on` fst) [(2,'a'), (3,'b'), (1, 'a'), (1,'b'), (1,'c'), (1,'a')]
[(1,'a'),(1,'c'),(1,'b'),(1,'a'),(2,'a'),(3,'b')]
If you want to sort by the entire pair, you can do that too
λ (1,'a') < (1,'b')
True
λ (1,'z') < (2,'a')
True
λ insert_sort_high (<) [(2,'a'), (3,'b'), (1,'a'),(1,'b'),(1,'c'), (1,'a')]
[(1,'a'),(1,'a'),(1,'b'),(1,'c'),(2,'a'),(3,'b')]
But I digress.
With that in mind all you really need to do is delete your tuple case, and clean up some typos.
insert_high :: (a -> a -> Bool) -> a -> [a] -> [a]
insert_high _ x [] = [x]
insert_high f x (y:ys)
| f x y = x:y:ys
| otherwise = y : insert_high f x ys
insert_sort_high _ [] = []
insert_sort_high f (x:xs) = insert_high f x (insert_sort_high f xs)
My task is to re-implement this function
divn :: Integer -> [Integer] -> [Integer]
divn _ [] = []
divn n (x:xs) | mod x n == 0 = x : divn n xs
| otherwise = divn n xs
using 'foldr'.
What I did:
divn' _ [] = []
divn' n (x:xs) = foldr (\x -> if (mod x n == 0) (x:) ([]++)) [] xs
I thought this would work. Actually it doesn't even compile, but says: "Parse error on input ")".
As I didn't find any errors, I decided to re-write if as if' an now its working...
if' True x _ = x
if' False _ x = x
divn' _ [] = []
divn' n (x:xs) = foldr (\x -> if' (mod x n == 0) (x:) ([]++)) [] xs
Does anyone know where's the error?
Thanks!
if needs a then and an else in Haskell,
(\x -> if (mod x n == 0) (x:) ([]++))
should be
(\x -> if (mod x n == 0) then (x:) else id)
Apart from what Daniel Fischer said, you don't need any separate cases: there's no recursion, the empty list case will be handled by foldr. In your code, the first x is always ignored! Correct is
divn' n xs = foldr (\x -> if x`mod`n == 0 then (x:) else id) [] xs
or, by η-reduction,
divn' n = foldr (\x -> if x`mod`n == 0 then (x:) else id) []
Of course, it would be far more idiomatic to simply do
divn'' n = filter ((==0) . (`mod`n))