I have just started learning Haskell and have written two functions, one for lists with even lengths and one for lists odd lengths. This means the 'even' function with [0..7] returns [0,7,2,5,4,3,6,1], and the 'odd' function with [0..8] returns [0,7,2,5,4,3,6,1,8] - these are the results I need.
However I after a lot of work I am still not able to combine them so that just one function works for both lists. Here are the functions and I wondered if more experienced Haskell coders know of a solution.
funcOdd :: [Int] -> [Int]
funcOdd [] = []
funcOdd (x:xs) = take (n+1) ((x*2) : (pred n - x):funcOdd(xs)) where n = length xs
funcEven :: [Int] -> [Int]
funcEven [] = []
funcEven (x:xs) = take (n+1) ((x*2) : (n - x):funcEven(xs)) where n = length xs
You can pattern match to separate the cases
fullFunction theList | even (length theList) = funcEven theList
fullFunction theList = funcOdd theList
when you call fullFunction, it will try the first case, checking if the length of the list is even. If this fails it will fallback to the second case.
Perhaps cleaner this way
func xs = zipWith const (go xs) xs
where go [] = []
go (x:xs) = 2*x : ((length xs)-off-x) : go xs
off = mod (length xs) 2
the only difference I see between the two functions is use of pred n vs n which is replaced with off(set) derived from the length of the original list.
zipWith const ... truncates the result with the length of the original list to replace take (n+1).
Related
I have an if-else statement, and in the else block I want it to first recurse to the function, except for the last two elements of the list, and then return two elements.
In the following function, after the if-else statement, I have 2 lines of code. however this doesnt compile. I believe the compiler reads these two lines as a single line of code. How do you fix that?
doubleEveryOther :: [Integer] -> [Integer] --outputs the input list, but every 2nd element(from the right) is doubled
doubleEveryOther [] = []
doubleEveryOther x = if (length x <2)
then
x
else
doubleEveryOther init (init x) -- These two lines
[2*last(init x), last x] -- These two lines
The compiler says:
* Couldn't match expected type: [Integer]
with actual type: [a0] -> [a0]
* Probable cause: `init' is applied to too few arguments
In the first argument of `doubleEveryOther', namely `init'
In the expression: doubleEveryOther init (init x)
In the expression:
[doubleEveryOther init (init x), 2 * last (init x), last x]
|
19 | [doubleEveryOther init (init x), 2*last(init x), last x]
|
You can not return two lists. If you have two results you want to combine, you use some function, like (++) :: [a] -> [a] -> [a].
That being said, you here don't need this. You can work with simple pattern matching:
doubleEveryOtherFromLeft :: Num a => [a] -> [a]
doubleEveryOtherFromLeft (x:y:xs) = 2*x : y : doubleEveryOtherFromLeft xs
doubleEveryOtherFromLeft xs = xs
then our doubleEveryOther can reverse the list twice:
doubleEveryOther:: Num a => [a] -> [a]
doubleEveryOther = reverse . doubleEveryOtherFromLeft . reverse
I think you are just missing the append operator ++:
doubleEveryOther (init (init x))
++ [2 * last (init x), last x]
I have an if-else statement, and in the else block I want it to first
recurse to the function, except for the last two elements of the list,
and then return two elements
OK. I sort of understand what you're doing. The function name is good - the best name is verb-noun, here doubleEveryOther. However, the code looks a lot like Lisp, probably Scheme - the repeated use of init gives it away. That's not how you write Haskell. (I also write Lisp in Haskell syntax too much...)
Haskell recursion works using pattern matching.
lst = [2,3,4]
1 : [2,3,4] -- [1,2,3,4]
lst = [1,2,3,4]
(x:xs) = lst -- x is 1, xs = [2,3,4]
So, in this case, you want to match your list against x:y:xs:
lst = [1,2,3,4]
(x:y:xs) = lst -- x is 1, y is 2, xs=[3,4]
Hence:
doubleEveryOther :: Num a => [a] -> [a]
doubleEveryOther [] = []
doubleEveryOther [x] = [2*x]
doubleEveryOther (x:y:xs) = (2*x):doubleEveryOther xs
Please note the number of special cases which need to be handled. If I am given an empty list, I should return an empty list. If I am given a single value, I need to double it (in analogy to your if .. else clause). If I am given two or more values, this matches x=first, y=second, xs=[] or more.
As for returning more than one value, you can return only one thing from a function. It can be a single value, a single tuple, a single list, and so on.
In this case, you have written a function which says doubleEveryOther - good - but then you want to return the last two values unchanged. You would be better taking off the last two values, running the simple doubleEveryOther and then bolting the last two values on the end. Otherwise, you are overburdening your function.
I'm taking a functional programming class and I'm having a hard time leaving the OOP mindset behind and finding answers to a lot of my questions.
I have to create a function that takes an ordered list and converts it into specified size sublists using a variation of fold.
This isn't right, but it's what I have:
splitList :: (Ord a) => Int -> [a] -> [[a]]
splitList size xs
| [condition] = foldr (\item subList -> item:subList) [] xs
| otherwise =
I've been searching and I found out that foldr is the variation that works better for what I want, and I think I've understood how fold works, I just don't know how I'll set up the guards so that when length sublist == size haskell resets the accumulator and goes on to the next list.
If I didn't explain myself correctly, here's the result I want:
> splitList 3 [1..10]
> [[1,2,3],[4,5,6],[7,8,9],[10]]
Thanks!
While Fabián's and chi's answers are entirely correct, there is actually an option to solve this puzzle using foldr. Consider the following code:
splitList :: Int -> [a] -> [[a]]
splitList n =
foldr (\el acc -> case acc of
[] -> [[el]]
(h : t) | length h < n -> (el : h) : t
_ -> [el] : acc
) []
The strategy here is to build up a list by extending its head as long as its length is lesser than desired. This solution has, however, two drawbacks:
It does something slightly different than in your example;
splitList 3 [1..10] produces [[1],[2,3,4],[5,6,7],[8,9,10]]
It's complexity is O(n * length l), as we measure length of up to n–sized list on each of the element which yields linear number of linear operations.
Let's first take care of first issue. In order to start counting at the beginning we need to traverse the list left–to–right, while foldr does it right–to–left. There is a common trick called "continuation passing" which will allow us to reverse the direction of the walk:
splitList :: Int -> [a] -> [[a]]
splitList n l = map reverse . reverse $
foldr (\el cont acc ->
case acc of
[] -> cont [[el]]
(h : t) | length h < n -> cont ((el : h) : t)
_ -> cont ([el] : acc)
) id l []
Here, instead of building the list in the accumulator we build up a function that will transform the list in the right direction. See this question for details. The side effect is reversing the list so we need to counter that by reverse application to the whole list and all of its elements. This goes linearly and tail-recursively tho.
Now let's work on the performance issue. The problem was that the length is linear on casual lists. There are two solutions for this:
Use another structure that caches length for a constant time access
Cache the value by ourselves
Because I guess it is a list exercise, let's go for the latter option:
splitList :: Int -> [a] -> [[a]]
splitList n l = map reverse . reverse . snd $
foldr (\el cont (countAcc, listAcc) ->
case listAcc of
[] -> cont (countAcc, [[el]])
(h : t) | countAcc < n -> cont (countAcc + 1, (el : h) : t)
(h : t) -> cont (1, [el] : (h : t))
) id l (1, [])
Here we extend our computational state with a counter that at each points stores the current length of the list. This gives us a constant check on each element and results in linear time complexity in the end.
A way to simplify this problem would be to split this into multiple functions. There are two things you need to do:
take n elements from the list, and
keep taking from the list as much as possible.
Lets try taking first:
taking :: Int -> [a] -> [a]
taking n [] = undefined
taking n (x:xs) = undefined
If there are no elemensts then we cannot take any more elements so we can only return an empty list, on the other hand if we do have an element then we can think of taking n (x:xs) as x : taking (n-1) xs, we would only need to check that n > 0.
taking n (x:xs)
| n > 0 = x :taking (n-1) xs
| otherwise = []
Now, we need to do that multiple times with the remainder so we should probably also return whatever remains from taking n elements from a list, in this case it would be whatever remains when n = 0 so we could try to adapt it to
| otherwise = ([], x:xs)
and then you would need to modify the type signature to return ([a], [a]) and the other 2 definitions to ensure you do return whatever remained after taking n.
With this approach your splitList would look like:
splitList n [] = []
splitList n l = chunk : splitList n remainder
where (chunk, remainder) = taking n l
Note however that folding would not be appropriate since it "flattens" whatever you are working on, for example given a [Int] you could fold to produce a sum which would be an Int. (foldr :: (a -> b -> b) -> b -> [a] -> b or "foldr function zero list produces an element of the function return type")
You want:
splitList 3 [1..10]
> [[1,2,3],[4,5,6],[7,8,9],[10]]
Since the "remainder" [10] in on the tail, I recommend you use foldl instead. E.g.
splitList :: (Ord a) => Int -> [a] -> [[a]]
splitList size xs
| size > 0 = foldl go [] xs
| otherwise = error "need a positive size"
where go acc x = ....
What should go do? Essentially, on your example, we must have:
splitList 3 [1..10]
= go (splitList 3 [1..9]) 10
= go [[1,2,3],[4,5,6],[7,8,9]] 10
= [[1,2,3],[4,5,6],[7,8,9],[10]]
splitList 3 [1..9]
= go (splitList 3 [1..8]) 9
= go [[1,2,3],[4,5,6],[7,8]] 9
= [[1,2,3],[4,5,6],[7,8,9]]
splitList 3 [1..8]
= go (splitList 3 [1..7]) 8
= go [[1,2,3],[4,5,6],[7]] 8
= [[1,2,3],[4,5,6],[7,8]]
and
splitList 3 [1]
= go [] 1
= [[1]]
Hence, go acc x should
check if acc is empty, if so, produce a singleton list [[x]].
otherwise, check the last list in acc:
if its length is less than size, append x
otherwise, append a new list [x] to acc
Try doing this by hand on your example to understand all the cases.
This will not be efficient, but it will work.
You don't really need the Ord a constraint.
Checking the accumulator's first sublist's length would lead to information flow from the right and the first chunk ending up the shorter one, potentially, instead of the last. Such function won't work on infinite lists either (not to mention the foldl-based variants).
A standard way to arrange for the information flow from the left with foldr is using an additional argument. The general scheme is
subLists n xs = foldr g z xs n
where
g x r i = cons x i (r (i-1))
....
The i argument to cons will guide its decision as to where to add the current element into. The i-1 decrements the counter on the way forward from the left, instead of on the way back from the right. z must have the same type as r and as the foldr itself as a whole, so,
z _ = [[]]
This means there must be a post-processing step, and some edge cases must be handled as well,
subLists n xs = post . foldr g z xs $ n
where
z _ = [[]]
g x r i | i == 1 = cons x i (r n)
g x r i = cons x i (r (i-1))
....
cons must be lazy enough not to force the results of the recursive call prematurely.
I leave it as an exercise finishing this up.
For a simpler version with a pre-processing step instead, see this recent answer of mine.
Just going to give another answer: this is quite similar to trying to write groupBy as a fold, and actually has a couple gotchas w.r.t. laziness that you have to bear in mind for an efficient and correct implementation. The following is the fastest version I found that maintains all the relevant laziness properties:
splitList :: Int -> [a] -> [[a]]
splitList m xs = snd (foldr f (const ([],[])) xs 1)
where
f x a i
| i <= 1 = let (ys,zs) = a m in ([], (x : ys) : zs)
| otherwise = let (ys,zs) = a (i-1) in (x : ys , zs)
The ys and the zs gotten from the recursive processing of the rest of list indicate the first and the rest of the groups into which the rest of the list will be broken up, by said recursive processing. So we either prepend the current element before that first subgroup if it is still shorter than needed, or we prepend before the first subgroup when it is just right and start a new, empty subgroup.
I am still trying to grasp the way Haskell and Functional Programming works, and I need help understanding why my function is not working. I am trying to create a function that takes a list of integers as a parameter and filters out/returns a sublist which contains any multiples of 3 from the first list. Here is my code:
module Main where
sublist = []
myFunc :: [Int] -> [Int]
myFunc [] = []
myFunc [t] = do
if t `mod` 3 == 0
then t : sublist
else myFunc []
myFunc (h:t) = do
if h `mod` 3 /= 0
then myFunc t
else do
h : sublist
myFunc t
This only returns a list containing the last value passed to the function, and still sublist = []. Thanks for any advice you can give me in advance.
I think you need to first switch over mentally to functional style.
for example, this is to get even numbers from a list
> filter even [1..10]
[2,4,6,8,10]
without using the existing functions you can implement the same functionality
filter' :: (a -> Bool) -> [a] -> [a]
filter' _ [] = []
filter' condition (x:xs) = if condition x
then x : filter' condition xs
else filter' condition xs
divisibleBy3 n = mod n 3 == 0
now, your program can be written as
filter' divisibleBy3 inputList
I'd like to reverse the first k elements of a list efficiently.
This is what I came up with:
reverseFirst :: Int -> [a] -> [a] -> [a]
reverseFirst 0 xs rev = rev ++ xs
reverseFirst k (x:xs) rev = reverseFirst (k-1) xs (x:rev)
reversed = reverseFirst 3 [1..5] mempty -- Result: [3,2,1,4,5]
It is fairly nice, but the (++) bothers me. Or should I maybe consider using another data structure? I want to do this many million times with short lists.
Let's think about the usual structure of reverse:
reverse = rev [] where
rev acc [] = acc
rev acc (x : xs) = rev (x : acc) xs
It starts with the empty list and tacks on elements from the front of the argument list till it's done. We want to do something similar, except we want to tack the elements onto the front of the portion of the list that we don't reverse. How can we do that when we don't have that un-reversed portion yet?
The simplest way I can think of to avoid traversing the front of the list twice is to use laziness:
reverseFirst :: Int -> [a] -> [a]
reverseFirst k xs = dis where
(dis, dat) = rf dat k xs
rf acc 0 ys = (acc, ys)
rf acc n [] = (acc, [])
rf acc n (y : ys) = rf (y : acc) (n - 1) ys
dat represents the portion of the list that is left alone. We calculate it in the same helper function rf that does the reversing, but we also pass it to rf in the initial call. It's never actually examined in rf, so everything just works. Looking at the generated core (using ghc -O2 -ddump-simpl -dsuppress-all -dno-suppress-type-signatures) suggests that the pairs are compiled away into unlifted pairs and the Ints are unboxed, so everything should probably be quite efficient.
Profiling suggests that this implementation is about 1.3 times as fast as the difference list one, and allocates about 65% as much memory.
Well, usually I'd just write splitAt 3 >>> first reverse >>> uncurry(++) to achieve the goal.
If you're anxious about performance, you can consider a difference list:
reverseFirstN :: Int -> [a] -> [a]
reverseFirstN = go id
where go rev 0 xs = rev xs
go rev k (x:xs) = go ((x:).rev) (k-1) xs
but frankly I wouldn't expect this to be a lot faster: you need to traverse the first n elements either way. Actual performance will depend a lot on what the compiler is able to fuse away.
I had an interview question, and it has been bugging me since then.
I have a function, fill, that does the computation like taking two lists and then replacing 2s in the second list, where ever there are 2s in the first list and also once 2s are filled in the second list from the first list, then it can flow till a 1 is encountered. For eg:
Two lists [2,1,2,1,2] [0,0,1,0,0] is passed, so the output I get is [2,2,1,2,2]. Now, I want to write a function that takes an argument something like this: [[2,1,2,1,2],[0,0,1,0,0],[0,0,0,0,0]], I want to apply my above function recursively till the end of this list of lists. So like first [2,1,2,1,2] [0,0,1,0,0] are passed to fill, then it should get the result [2,2,1,2,2], then [2,2,1,2,2] and [0,0,0,0,0] should be passed, getting the result [2,2,2,2,2]. How can I do that?
EDIT:
I did this:
fillAll::[[Int]]->[Int]
fillAll [] = []
fillAll (x:xs) =
(foldl' seep x xs) $
helper2 x
helper2:: [Int] -> Bool
helper2 lst =
if 2 `elem` lst then True else False
So, you have your function fill:
fill :: [Int] -> [Int] -> [Int]
And you want to turn this into a function which takes a list of lists:
fillRec :: [[Int]] -> [Int]
This is a natural case for a fold. This repeatedly 'folds' each element of a list together using a combining function. We need to make sure the list isn't empty:
fillRec [] = []
fillRec (x : xs) = foldl fill x xs
This version of foldl (e.g. folds from the left, rather than from the right) is non-strict, which can cause large memory accumulation. It's better to use the strict variant foldl' from Data.List:
fillRec (x : xs) = foldl' fill x xs
I'm going to assume that you already have fill :: [Int] -> [Int] -> [Int] defined. If so, this problem is pretty easy to solve using a fold. Explicitly, you could do something like
fillAll :: [[Int]] -> [Int]
fillAll [] = []
fillAll (x:xs) = go x xs
where
go first [] = first
go first (second:rest) = go (fill first second) rest
Or you can use one of the built-in folds:
fillAll [] = []
fillAll (x:xs) = foldl fill x xs
but as Impredicative points out, you'll have better performance with foldl' from Data.List