How can I propagate information backwards in a recursive call-chain?
For example:
f :: [Int] -> [Int]
f (x:xs)
| x `mod` 17 = ...
| otherwise = (x + 1) : f xs
f [] = []
I want to stop the evaluation at the ..., and I also want to propagate that information back to the caller (the fact that it stopped). I tried to use return types like Maybe, but then I had to pattern-match the recursive call, and thus lost tail-call optimization, since I had to evaluate it after the call returned (note: one could easily transform the above code to TR form, but I left it like this for easier understanding).
Can you come up with a better solution that still benefits from TCO?
You can always use extra parameters, and return a tuple with the accumulated results. This way you still benefit from TCO, and get the information you needed.
An example:
f :: [Int] -> Bool -> [Int] -> (Bool, [Int])
f (x:xs) l accum
| x `mod` 17 == 0 = (False, accum)
| otherwise = f xs l ((x+1) : accum)
f [] l accum = (True, accum)
Or in a more elegant way:
data CheckedValue a = Valid a | Invalid a
deriving Show
f :: [Int] -> [Int] -> CheckedValue [Int]
f (x:xs) accum
| x `mod` 17 == 0 = Invalid accum
| otherwise = f xs ((x+1) : accum)
f [] accum = Valid accum
Note: These functions also reverse the list, but pay no attention to that.
Related
I need some kind of fold which can terminate if I already have the data I want.
For example I need to find first 3 numbers which are greater than 5. I decided to use Either for termination and my code looks like this:
terminatingFold :: ([b] -> a -> Either [b] [b]) -> [a] -> [b]
terminatingFold f l = reverse $ either id id $ fold [] l
where fold acc [] = Right acc
fold acc (x:xs) = f acc x >>= flip fold xs
first3NumsGreater5 acc x =
if length acc >= 3
then Left acc
else Right (if x > 5 then (x : acc) else acc)
Are there some more clever/generic approaches?
The result of your function is a list, and it would be desirable if it were produced lazily, that is, extracting one item from the result should only require evaluating the input list up until the item is found there.
Unfolds are under-appreciated for these kinds of tasks. Instead of focusing on "consuming" the input list, let's think of it as a seed from which (paired with some internal accumulator) we can produce the result, element by element.
Let's define a Seed type that contains a generic accumulator paired with the as-yet unconsumed parts of the input:
{-# LANGUAGE NamedFieldPuns #-}
import Data.List (unfoldr)
data Seed acc input = Seed {acc :: acc, pending :: [input]}
Now let's reformulate first3NumsGreater5 as a function that either produces the next output element from the Seed, of signals that there aren't any more elements:
type Counter = Int
first3NumsGreater5 :: Seed Counter Int -> Maybe (Int, Seed Counter Int)
first3NumsGreater5 (Seed {acc, pending})
| acc >= 3 =
Nothing
| otherwise =
case dropWhile (<= 5) pending of
[] -> Nothing
x : xs -> Just (x, Seed {acc = succ acc, pending = xs})
Now our main function can be written in terms of unfoldr:
unfoldFromList ::
(Seed acc input -> Maybe (output, Seed acc input)) ->
acc ->
[input] ->
[output]
unfoldFromList next acc pending = unfoldr next (Seed {acc, pending})
Putting it to work:
main :: IO ()
main = print $ unfoldFromList first3NumsGreater5 0 [0, 6, 2, 7, 9, 10, 11]
-- [6,7,9]
Normally an early termination-capable fold is foldr with the combining function which is non-strict in its second argument. But, its information flow is right-to-left (if any), while you want it left-to-right.
A possible solution is to make foldr function as a left fold, which can then be made to stop early:
foldlWhile :: Foldable t
=> (a -> Bool) -> (r -> a -> r) -> r
-> t a -> r
foldlWhile t f a xs = foldr cons (\acc -> acc) xs a
where
cons x r acc | t x = r (f acc x)
| otherwise = acc
You will need to tweak this for t to test the acc instead of x, to fit your purposes.
This function is foldlWhile from https://wiki.haskell.org/Foldl_as_foldr_alternative, re-written a little. foldl'Breaking from there might fit the bill a bit better.
foldr with the lazy reducer function can express corecursion perfectly fine just like unfoldr does.
And your code is already lazy: terminatingFold (\acc x -> Left acc) [1..] => []. That's why I'm not sure if this answer is "more clever", as you've requested.
edit: following a comment by #danidiaz, to make it properly lazy you'd have to code it as e.g.
first3above5 :: (Foldable t, Ord a, Num a)
=> t a -> [a]
first3above5 xs = foldr cons (const []) xs 0
where
cons x r i | x > 5 = if i==2 then [x]
else x : r (i+1)
| otherwise = r i
This can be generalized further by abstracting the test and the count.
Of course it's just reimplementing take 3 . filter (> 5), but shows how to do it in general with foldr.
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 have the following function that determines the maximum element of a given list.
maxList :: Ord a => [a] -> a
maxList l =
let iMaxList :: Ord a => [a] -> a
iMaxList [] = error( "Empty list" )
iMaxList [x] = x
iMaxList ( x:xs )
| x > t = x
| otherwise = t
where t = iMaxList xs
in iMaxList l
Yet, it doesn't use tail recursion and I'd like it to do so.
I tried to use an accumulator to comply with the tail recursion principle in Haskell.
maxList :: Ord a => [a] -> a
maxList ( x:xs ) = loop( xs, x )
where loop( x:xs, m )
| ( null xs ) = m
| ( x >= m ) = loop( xs, x )
| otherwise = loop( xs, m )
Yet, it logically fails because of this guard (null xs) = m. Indeed, if we take the list [1,2,3,4], 4will never be evaluated.
How can I fix that?
listMax :: Ord a => [a] -> a
listMax [] = error "Tried to find maximum of an empty list."
listMax (x:xs) = listMax' xs x where
listMax' :: Ord a => [a] -> a -> a
listMax' [] y = y
listMax' (x:xs) y | x > y = listMax' xs x
| otherwise = listMax' xs y
In this case, y is the accumulating parameter that holds the maximum value found so far. Brief proof of correctness: the algorithm terminates because each tail-recursive call removes one element from the input list until it is empty. The final value of y it returns is the maximum because, for every other element x in the input, either y > x or y > z > x for some z after x and before y. (This assumes that > is transitive.)
You could also write the helper function this way:
listMax' :: Ord a => [a] -> a -> a
listMax' [] y = y
listMax' (x:xs) y = listMax' xs (max x y)
And this implementation does the same thing:
listMax2 :: Ord a => [a] -> a
listMax2 [] = error "Tried to find maximum of an empty list."
listMax2 list = foldl1 max list
The foldl1 function is a tail-recursive lazy evaluation from front to back, but the strict foldl1' version or foldr1 might be more efficient in this case. The first version is closer to strict evaluation than lazy.
I guess this is what your are searching for:
maxList' :: Ord a => [a] -> a
maxList' [] = error "Empty List"
maxList' [x] = x
maxList' (x:y:xs) = maxList' (max x y:xs)
The function uses the same list that is processing to store the biggest number found so far. It seems to comply with the tail recursion definition, ie: the recursive call is the very last thing in the computation of the function.
Don't worry about it.
I wrote the following in a file:
module MaxList (maxList) where
import Data.List
maxList :: Ord a => [a] -> a
maxList = foldl1' max
Then I compiled it with -O2 -ddump-simpl, to have a look at the optimised Core. After a bit of cleaning up - GHC generates a lot of variables with names that are difficult to read - the generated code looks like this:
maxList [] = error "empty list"
maxList (x:xs) = go xs x
where go ys y =
case ys of
[] -> y;
(z:zs) -> case y of -- force y to WHNF before continuing
_ -> go zs (max y z)
go is tail recursive. In fact it's the same as the code in #Davislor's answer! I used foldl1' - a high-level control structure - and GHC generated exactly the code that you would've written by hand if you wanted to write a tail recursive loop.
Haskell's philosophy is that you should use high-level tools like folds, unfolds, monads, classes, etc, and rely on the compiler to generate good code. There certainly is an art to writing code which GHC will do a good job of optimising - you don't always get it for free - but you usually shouldn't need to unroll high-level structures into low-level loops because GHC is good at that.
my title might be a bit off and i'll try to explain a bit better what i'm trying to achieve.
Basically let's say i have a list:
["1234x4","253x4",2839",2845"]
Now i'd like to add all the positions of the strings which contain element 5 to a new list. On a current example the result list would be:
[1,3]
For that i've done similar function for elem:
myElem [] _ = False
myElem [x] number =
if (firstCheck x) then if digitToInt(x) == number then True else False else False
myElem (x:xs) number =
if (firstCheck x) then (if digitToInt(x) == number then True else myElem xs number) else myElem xs number
where firstCheck x checks that the checked element isn't 'x' or '#'
Now in my current function i get the first element position which contains the element, however my head is stuck around on how to get the full list:
findBlock (x:xs) number arv =
if myElem x number then arv else findBlock xs number arv+1
Where arv is 0 and number is the number i'm looking for.
For example on input:
findBlock ["1234x4","253x4",2839",2845"] 5 0
The result would be 1
Any help would be appreciated.
The function you want already exists in the Data.List module, by the name of findIndices. You can simply use (elem '5') as the predicate.
http://hackage.haskell.org/package/base-4.8.1.0/docs/Data-List.html#v:findIndices
If, for some reason, you're not allowed to use the built-in one, it comes with a very pretty definition (although the one actually used has a more complicated, more efficient one):
findIndices p xs = [ i | (x,i) <- zip xs [0..], p x]
By the way, I found this function by searching Hoogle for the type [a] -> (a -> Bool) -> [Int], which (modulo parameter ordering) is obviously the type such a function must have. The best way to find out of Haskell has something is to think about the type it would need to have and search Hoogle or Hayoo for the type. Hoogle is better IMO because it does slightly fuzzy matching on the type; e.g. Hayoo wouldn't find the function here by the type I've given, because it take the arguments in the reverse order.
An implementation of findIndices, for instructional purposes:
findIndices ok list = f list 0 where
f [] _ = []
f (x:xs) ix
| ok x = ix : f xs (ix+1)
| otherwise = f xs (ix+1)
Use it like findIndices (elem '5') my_list_o_strings
You're trying to work your way through a list, keeping track of where you are in the list. The simplest function for doing this is
mapWithIndex :: (Int -> a -> b) -> [a] -> [b]
mapWithIndex = mwi 0 where
mwi i _f [] = i `seq` []
mwi i f (x:xs) = i `seq` f i x : mwi (i+1) f xs
This takes a function and a list, and applies the function to each index and element. So
mapWithIndex (\i x -> (i, x)) ['a', 'b', 'c'] =
[(0,'a'), (1,'b'),(2,'c')]
Once you've done that, you can filter the list to get just the pairs you want:
filter (elem '5' . snd)
and then map fst over it to get the list of indices.
A more integrated approach is to use foldrWithIndex.
foldrWithIndex :: (Int -> a -> b -> b) -> b -> [a] -> b
foldrWithIndex = fis 0 where
fis i _c n [] = i `seq` n
fis i c n (x:xs) = i `seq` c i x (fis (i+1) c n xs)
This lets you do everything in one step.
It turns out that you can implement foldrWithIndex using foldr pretty neatly, which makes it available for any Foldable container:
foldrWithIndex :: (Foldable f, Integral i) =>
(i -> a -> b -> b) -> b -> f a -> b
foldrWithIndex c n xs = foldr go (`seq` n) xs 0 where
go x r i = i `seq` c i x (r (i + 1))
Anyway,
findIndices p = foldrWithIndex go [] where
go i x r | p x = i : r
| otherwise = r
I tried to make a very short code, because we have a reglementation that favors the shortest code.
We have to create a function that turns a list into a new list of ascending and descending lists in the same order: For example. [1,6,2,1,7,3,2,8,4], becomes [[1,6],[2,1],[7],[3,2],[8],[4]]
So i tried to do the following:
func :: Ord a => [a] -> [[a]]
func xs = f1 d [a]
f1 [] ys = [c]
f1 xs ys | a >= b = d `f1` a:ys
| otherwise = c: d `f2` [a]
f2 [] ys = [c]
f2 xs ys | a < b = d `f2` a:ys
| otherwise = c : d `f1` [a]
where a = head xs
b = head ys
c = reverse ys
d = tail xs
But i get
parse error on input '='
on the line "b = head ys".
I thought it is possible to define multiple functions in the where block?
Other indentations created errors like a lot of
not in scope 'a'
not in scope 'b'
not in scope 'c'
not in scope 'd'
or
parse error on input 'b'
I have to make it that way to save some tokens/ have shorter code.
That's how it looks to the compiler:
func :: Ord a => [a] -> [[a]]
func xs = f1 d [a]
f1 [] ys = [c]
f1 xs ys | a >= b = d `f1` a:ys
| otherwise = c: d `f2` [a]
f2 [] ys = [c]
f2 xs ys | a < b = d `f2` a:ys
| otherwise = c : d `f1` [a]
where a = head xs
b = head ys
c = reverse ys
d = tail xs
So for the compiler, the lines in the where clause after the first look like continuations of that line, and of course you can't have multiple = without an intervening semicolon on one line.
You should never mix tabs and spaces (you shouldn't ever use tabs, actually). And if you use tabs, configure your editor to interpret them as eight spaces.
And, the where clause only scopes over the last equation, so there are no a, b, c, d in scope in the first four equations for func.
You have a more fundamental problem than indentation: a where block is local to a single function case. You're trying to use your where block to provide bindings (e.g. a, b, c, d) to a whole bunch of functions. This won't work.
To clarify, this correctly indented code won't work:
foo :: Int -> Int
foo 0 = a
foo 1 = b
where a = 2
b = 3
You'll get an error like Not in scope: `a'. This is because the where only extends over the foo 1 case; it doesn't even go to the foo 0 case, much less any other function.
Your code, on the other hand, seems to expect the where block to work for all your functions. To have bindings that can be seen by different functions, you have to put them at the same level of scope as the functions themselves.
Also, Haskell indentation is a little finnicky. You really should avoid tabs; it also really helps to have an editor that understands Haskell properly. I've found Emacs is very good here--I never have to worry about Haskell indentation with Emacs.
Emacs might have a bit of a learning curve (you should do the tutorial), but I think it's well worth it. You'll also have to install the Haskell mode. If you get the newest version of Emacs, you should be able to do this using the package manager.
Your error messages are because you're mixing tabs and spaces. It's best to just use spaces.
Now, if you're writing
a = head xs
b = head ys
c = reverse ys
d = tail xs
then
xs = (a:ds)
ys = (b:es)
Let's rewrite your function with pattern matching:
func :: Ord a => [a] -> [[a]]
func [] = []
func (a:ds) = f1 ds [a]
f1 [] ys = [reverse ys]
f1 (a:ds) (b:es) | a >= b = ds `f1` (a:b:es)
| otherwise = reverse (b:es): ds `f2` [a]
f2 [] ys = [reverse ys]
f2 (a:ds) (b:es) | a < b = ds `f2` (a:b:es)
| otherwise = reverse (b:es) : ds `f1` [a]
I know this is longer, but bear with me. f1 is really the same as f2, but with the comparison changed. Let's get a function no to negate a comparison, so that (no (>=)) x y = not (x >= y):
no cmp x y = not (cmp x y)
In fact, we can write this as
no = ((not.).)
r = reverse
func' (a:ds) = f (>=) ds [a]
f :: Ord a => (a -> a -> Bool) -> [a] -> [a] -> [[a]]
f _ [] ys = [r ys]
f cp (a:ds) ys#(b:es) | cp a b = f cp ds (a:ys)
| True = r ys : f (no cp) ds [a]
Now that is shorter.