Why isn't iterate defined like
iterate :: (a -> a) -> a -> [a]
iterate f x = xs where xs = x : map f xs
in the Prelude?
Tying the knot like that doesn't appear to increase sharing.
Contrast with:
cycle xs = let x = xs ++ x in x
Tying the knot here has the effect of creating a circular linked list in memory. x is its own tail. There's a real gain.
Your suggested implementation doesn't increase sharing over the naive implementation. And there's no way for it to do so in the first place - there's no shared structure in something like iterate (+1) 0 anyway.
There is no knot tying going on in your version, it just maintains a pointer one notch back on the produced list, to find the input value there for the next iteration. This means that each list cell can't be gc-ed until the next cell is produced.
By contrast, the Prelude's version uses iterate's call frame for that, and since it's needed only once, a good compiler could reuse that one frame and mutate the value in it, for more optimized operation overall (and list's cells are independent of each other in that case).
The Prelude definition, which I include below for clarity, has no overhead needed to call map.
iterate f x = x : iterate f (f x)
Just for fun, I made a small quick program to test your iterate vs the Prelude's - just to reduce to normal form take 100000000 $ iterate (+1) 0 (this is a list of Ints). I only ran 5 tests, but your version ran for 7.833 (max 7.873 min 7.667) while the Prelude's was at 7.519 (max 7.591 min 7.477). I suspect the time difference is the overhead of map getting called.
Second reason is simply: readability.
Related
I was introduced to the use of fold in defining function. I have an idea how that works but im not sure why one should do it. To me, it feels like just simplifying name of data type and data value ... Would be great if you can show me examples where it is significant to use fold.
data List a = Empty | (:-:) a (List a)
--Define elements
List a :: *
[] :: List a
(:) :: a -> List a -> List a
foldrList :: (a -> b -> b) -> b -> List a -> b
foldrList f e Empty = e
foldrList f e (x:-:xs) = f x (foldrList f e xs)
The idea of folding is a powerful one. The fold functions (foldr and foldl in the Haskell base library) come from a family of functions called Higher-Order Functions (for those who don't know - these are functions which take functions as parameters or return functions as their output).
This allows for greater code clarity as the intention of the program is more clearly expressed. A function written using fold functions strongly indicates that there is an intention to iterate over the list and apply a function repeatedly to obtain an output. Using the standard recursive method is fine for simple programs but when complexity increases it can become difficult to understand quickly what is happening.
Greater code re-use can be achieved with folding due to the nature of passing in a function as the parameter. If a program has some behaviour that is affected by the passing of a Boolean or enumeration value then this behaviour can be abstracted away into a separate function. The separate function can then be used as an argument to fold. This achieves greater flexibility and simplicity (as there are 2 simpler functions versus 1 more complex function).
Higher-Order Functions are also essential for Monads.
Credit to the comments for this question as well for being varied and informative.
Higher-order functions like foldr, foldl, map, zipWith, &c. capture common patterns of recursion so you can avoid writing manually recursive definitions. This makes your code higher-level and more readable: instead of having to step through the code and infer what a recursive function is doing, the programmer can reason about compositions of higher-level components.
For a somewhat extreme example, consider a manually recursive calculation of standard deviation:
standardDeviation numbers = step1 numbers
where
-- Calculate length and sum to obtain mean
step1 = loop 0 0
where
loop count sum (x : xs) = loop (count + 1) (sum + x) xs
loop count sum [] = step2 sum count numbers
-- Calculate squared differences with mean
step2 sum count = loop []
where
loop diffs (x : xs) = loop ((x - (sum / count)) ^ 2 : diffs) xs
loop diffs [] = step3 count diffs
-- Calculate final total and return square root
step3 count = loop 0
where
loop total (x : xs) = loop (total + x) xs
loop total [] = sqrt (total / count)
(To be fair, I went a little overboard by also inlining the summation, but this is roughly how it may typically be done in an imperative language—manually looping.)
Now consider a version using a composition of calls to standard functions, some of which are higher-order:
standardDeviation numbers -- The standard deviation
= sqrt -- is the square root
. mean -- of the mean
. map (^ 2) -- of the squares
. map (subtract -- of the differences
(mean numbers)) -- with the mean
$ numbers -- of the input numbers
where -- where
mean xs -- the mean
= sum xs -- is the sum
/ fromIntegral (length xs) -- over the length.
This more declarative code is also, I hope, much more readable—and without the heavy commenting, could be written neatly in two lines. It’s also much more obviously correct than the low-level recursive version.
Furthermore, sum, map, and length can all be implemented in terms of folds, as well as many other standard functions like product, and, or, concat, and so on. Folding is an extremely common operation on not only lists, but all kinds of containers (see the Foldable typeclass), because it captures the pattern of computing something incrementally from all elements of a container.
A final reason to use folds instead of manual recursion is performance: thanks to laziness and optimisations that GHC knows how to perform when you use fold-based functions, the compiler may fuse a series of folds (maps, &c.) together into a single loop at runtime.
I want to make a function that creates an infinite list that takes two numbers and an operator as input so it can generate arithmetic and geometric sequences.
infiniteList:: (Floating a)=>a->(a->a->a)->a->[a]
infiniteList start operation changeby =
start:[(operation x changeby)| x<-(infiniteList start operation changeby)]
the code compiles and works properly: infiniteList 1 (*) 2 generates a list starting from 1 and subsequent numbers are double its predecessor.
Now I'm having trouble figuring out the computational complexity "to calculate the nth element of the list". Technically it is doing one operation to figure out each element of the list. However, if you were after the (2^k +1) term, I would have to wait for the computer to finish calculating 2^(k+1) elements first.
I hope I'm explaining this properly, so basically I think the program produces the elments in 2^k batches where k is an integer, so you could potentially be waiting for ( 2^(k+1)-2^k) time to calculate the (2^k +1)th integer. So what is the computational complexity "to calculate the nth element of the list"?
A key tool is the following rule:
When analyzing the performance (not the totality) of a binding, you are allowed to assume, when analyzing its right-hand-side, that the binding itself has been fully evaluated.
You are defining infiniteList, so you are allowed to assume that in the RHS, the infiniteList binding has been fully evaluated. That, unfortunately, isn't useful, because infiniteList is just a function, and fully evaluating it just gives you the function!
But you can use this reasoning tool to figure out a fix: you have to bind the right thing.
infiniteList :: a -> (a -> a -> a) -> a -> [a]
infiniteList start operation changeby =
let result =
start : [operation x changeby | x <- result]
in result
Now you have a useful binding, result, which you can assume is fully evaluated! In the RHS, you now have, essentially,
start : map (\x -> operation x changeby) result
which is clearly O(n).
Indeed with the first definition,
> infiniteList 1 (*) 2 !! 10000
takes longer than I wish to wait, but with the modified definition, it takes a mere 0.04 seconds even in GHCi.
The run time depends a lot on how GHC decides to evaluate it.
To simplify things, consider this version of the function:
inf a f = a : [ f x | x <- inf a f ]
If GHC performed common sub-expression elimination on int a f, it could decide to evaluate it as if it had been written:
inf a f = let r = a : [ f x | x <- r ]
in r
and this runs in linear time.
I'm not sure where you are getting the "batches" idea from. Below is a transcript of the first few elements of the list. From that, I think you should be able to figure out the complexity.
What's the first element of the list? It is start, because infiniteList is defined as start:[something], and the first element of any list of that form is start.
What is the second element of the list? We certainly need to consult the [something] portion of the list above. The first element of that sublist is operation x changeby where x is the first element of infiniteList. We decided already that the first element is start, so the second element is operation start changeby, which is exactly what we wanted. What do we have to compute to get the second element? Just the first, plus the operation.
What is the third element of the list? It's the second element of [something], which is operation x changeby where x is the second element of infiniteList. Fortunately, we just calculated what that is...
What do we have to compute to get the third element? Just the first and second, plus the operation.
Although it doesn't directly answer the question, you should ask yourself what complexity you expect the function to have. How much work needs to be done to get the nth element? It's possible that your implementation in code is worse, but it might help you think about your code differently.
Just do some math, assume calculate nth item requires T(n) calculations, as
[(operation x changeby)| x<-(infiniteList start operation changeby)]
suggests, we need to know sub problem T(n-1), and the full list comprehension have n-1 operations, and then concat star:... operation is efficient, and have 1 calculation, so
T(n) = T(n-1) + (n - 1) + 1 = T(n-1) + n -> O(n^2)
Actually, you can "feel" the time complexity just by running some examples. Let f n = (infiniteList 0 (+) 1) !! n, then run f 10, f 100, f 1000, f 10000, you can see the difference.
Usually, when n=1000 runs in no time, n=10000 run some time like 1 or 2 seconds, and n=100000 run forever, it is usually O(n^2).
BTW, there is an O(n) approach:
infi :: a -> (a -> a -> a) -> a -> [a]
infi x f s = x : infi (f x s) f s
You can do some math and run some examples to feel the difference.
One strategy that sometimes helps with recursion is to expand it out a few times to get a better idea of what's going on. Let's try that:
infiniteList start operation changeby =
start:[(operation x changeby) | x <-
start:[(operation x changeby) | x <-
start:[(operation x changeby) | x <-
start:[(operation x changeby) | x <-
start:[(operation x changeby) | x <- (infiniteList start operation changeby)]]]]]
We can see the first element in the list is going to be start as expected. Then the second element will be start from the first recursive call passed through operation x changeby. What will the third item be? Well it'll be the second item of the first recursive call, so it'll be start passed through two calls of operation x changeby. Now the pattern emerges! In general, the nth item of infiniteList will be start with operation x changeby called on it n-1 times. This is rather unfortunate because ,as any student of computer science knows, 1 + 2 + ... + n - 1 = n(n-1)/2 = O(n^2).
There is, of course, a much more efficient way to write this function. Instead of applying operation x changeby to start n-1 times to get the nth item, why don't we just apply it once to the previous item? This will give us an O(n) solution. For example, we can use unfoldr from Data.List:
import Data.List (unfoldr)
infiniteList start operation changeby =
unfoldr (\x -> Just (x, operation x changeby)) start
I want an intermediate result computed before generating the new one to get the benefit of memoization.
import qualified Data.Map.Strict as M
import Data.List
parts' m = newmap
where
n = M.size m + 1
lists = nub $ map sort $
[n] : (concat $ map (\i -> map (i:) (M.findWithDefault [] (n-i) m)) [1..n])
newmap = seq lists (M.insert n lists m)
But, then if I do
take 2000 (iterate parts' (M.fromList [(1,[[1]])]))
It still completes instantaneously.
(Can using an Array instead of a Map help?)
Short answer:
If you need to calculate the entire list/array/map/... at once, you can use deepseq as #JoshuaRahm suggests, or the ($!!) operator.
The answer below how you can enforce strictness, but only on level-1 (it evaluates until it reaches a datastructure that may contain (remainders) of expression trees).
Furthermore the answer argues why laziness and memoization are not (necessarily) opposites of each other.
More advanced:
Haskell is a lazy language, it means it only calculates something, if it is absolutely necessary. An expression like:
take 2000 (iterate parts' (M.fromList [(1,[[1]])]))
is not evaluated immediately: Haskell simply stores that this has to be calculated later. Later if you really need the first, second, i-th, or the length of the list, it will evaluate it, and even then in a lazy fashion: if you need the first element, from the moment it has found the way to calculate that element, it will represent it as:
element : take 1999 (<some-expression>)
You can however force Haskell to evaluate something strictly with the exclamation mark (!), this is called strictness. For instance:
main = do
return $! take 2000 (iterate parts' (M.fromList [(1,[[1]])]))
Or in case it is an argument, you can use it like:
f x !y !z = x+y+z
Here you force Haskell to evaluate y and z before "increasing the expression tree" as:
expression-for-x+expression-for-y+expression-for-z.
EDIT: if you use it in a let pattern, you can use the bang as well:
let !foo = take 2000 (iterate parts' (M.fromList [(1,[[1]])])) in ...
Note that you only collapse the structure to the first level. Thus let !foo will more or less only evaluate up to (_:_).
Note: note that memoization and lazyness are not necessary opposites of each other. Consider the list:
numbers :: [Integer]
numbers = 0:[i+(sum (genericTake i numbers))|i<-[1..]]
As you can see, calculating a number requires a large amount of computational effort. Numbers is represented like:
numbers ---> (0:[i+(sum (genericTake i numbers))|i<-[1..]])
if however, I evaluate numbers!!1, it will have to calculate the first element, it returns 1; but the internal structure of numbers is evaluated as well. Now it looks like:
numbers (0:1:[i+(sum (genericTake i numbers))|i<-[2..]])
The computation numbers!!1 thus will "help" future computations, because you will never have to recalcuate the second element in the list.
If you for instance calculate numbers!!4000, it will take a few seconds. Later if you calculate numbers!!4001, it will be calculated almost instantly. Simply because the work already done by numbers!!4000 is reused.
Arrays might be able to help, but you can also try taking advantage of the deepseq library. So you can write code like this:
let x = take 2000 (iterate parts' (M.fromList [(1,[[1]])])) in do
x `deepseq` print (x !! 5) -- takes a *really* long time
print (x !! 1999) -- finishes instantly
You are memoizing the partitions functions, but there are some drawbacks to your approach:
you are only memoizing up to a specific value which you have to specify beforehand
you need to call nub and sort
Here is an approach using Data.Memocombinators:
import Data.Memocombinators
parts = integral go
where
go k | k <= 0 = [] -- for safety
go 1 = [[1]]
go n = [[n]] ++ [ (a : p) | a <- [n-1,n-2..1], p <- parts (n-a), a >= head p ]
E.g.:
ghci> parts 4
[[4],[3,1],[2,2],[2,1,1],[1,1,1,1]]
This memoization is dynamic, so only the values you actually access will be memoized.
Note how it is constructed - parts = integral go, and go uses parts for any recursive calls. We use the integral combinator here because parts is a function of an Int.
Thinking Functionally with Haskell provides the following code for calculating the mean of a list of Float's.
mean :: [Float] -> Float
mean [] = 0
mean xs = sum xs / fromIntegral (length xs)
Prof. Richard Bird comments:
Now we are ready to see what is really wrong with mean: it has a space leak. Evaluating mean [1..1000] will cause the list to be expanded and retained in memory after summing because there is a second pointer to it, namely in the computation of its length.
If I understand this text correctly, he's saying that, if there was no pointer to xs in the length computation, then the xs memory could've been freed after calculating the sum?
My confusion is - if the xs is already in memory, isn't the length function simply going to use the same memory that's already being taken up?
I don't understand the space leak here.
The sum function does not need to keep the entire list in memory; it can look at an element at a time then forget it as it moves to the next element.
Because Haskell has lazy evaluation by default, if you have a function that creates a list, sum could consume it without the whole list ever being in memory (each time a new element is generated by the producing function, it would be consumed by sum then released).
The exact same thing happens with length.
On the other hand, the mean function feeds the list to both sum and length. So during the evaluation of sum, we need to keep the list in memory so it can be processed by length later.
[Update] to be clear, the list will be garbage collected eventually. The problem is that it stays longer than needed. In such a simple case it is not a problem, but in more complex functions that operate on infinite streams, this would most likely cause a memory leak.
Others have explained what the problem is. The cleanest solution is probably to use Gabriel Gonzalez's foldl package. Specifically, you'll want to use
import qualified Control.Foldl as L
import Control.Foldl (Fold)
import Control.Applicative
meanFold :: Fractional n => Fold n (Maybe n)
meanFold = f <$> L.sum <*> L.genericLength where
f _ 0 = Nothing
f s l = Just (s/l)
mean :: (Fractional n, Foldable f) => f n -> Maybe n
mean = L.fold meanFold
if there was no pointer to xs in the length computation, then the xs memory could've been freed after calculating the sum?
No, you're missing the important aspect of lazy evaluation here. You're right that length will use the same memory as was allocated during the sum call, the memory in which we had expanded the whole list.
But the point here is that allocating memory for the whole list shouldn't be necessary at all. If there was no length computation but only the sum, then memory could've been freed during calculating the sum. Notice that the list [1..1000] is lazily generated only when it is consumed, so in fact the mean [1..1000] should run in constant space.
You might write the function like the following, to get an idea of how to avoid such a space leak:
import Control.Arrow
mean [] = 0
mean xs = uncurry (/) $ foldr (\x -> (x+) *** (1+)) (0, 0) xs
-- or more verbosely
mean xs = let (sum, len) = foldr (\x (s, l) -> (x+s, 1+l)) (0, 0)
in sum / len
which should traverse xs only once. However, Haskell is damn lazy - and computes the first tuple components only when evaluating sum and the second ones only later for len. We need to use some more tricks to actually force the evaluation:
{-# LANGUAGE BangPatterns #-}
import Data.List
mean [] = 0
mean xs = uncurry (/) $ foldl' (\(!s, !l) x -> (x+s, 1+l)) (0,0) xs
which really runs in constant space, as you can confirm in ghci by using :set +s.
The space leak is that the entire evaluated xs is held in memory for the length function. This is wasteful, as we aren't going to be using the actual values of the list after evaluating sum, nor do we need them all in memory at the same time, but Haskell doesn't know that.
A way to remove the space leak would be to recalculate the list each time:
sum [1..1000] / fromIntegral (length [1..1000])
Now the application can immediately start discarding values from the first list as it is evaluating sum, since it is not referenced anywhere else in the expression.
The same applies for length. The thunks it generates can be marked for deletion immediately, since nothing else could possibly want it evaluated further.
EDIT:
Implementation of sum in Prelude:
sum l = sum' l 0
where
sum' [] a = a
sum' (x:xs) a = sum' xs (a+x)
I can't post the my function that is giving me bother, but basically, I'm having run time problems in my implementation of an A* Search using a heuristic which applies the ceiling function onto the straight line distance between two points. Throughout the function I refer to a list I define at the end using "where", and I believe it is a function within this list causing the runtime problems (as when I remove it, it runs quickly), but I don't understand why because it isn't a complicated function at all. This leads me to believe that the function may be trying to recreate the list every time it is referenced, instead of just once and using the already formed list each time which may be slowing it down, and causing runtimes to increase exponentionally.
i.e. As a basic example, I have referenced "myList" 3 times in the function.
function :: Int -> [Int]
function x = head (myList) : (maximum (myList) : minimum (myList))
where myList = [snd pair | pair <- (zip [0..] [sortBy compare [5*x,3-x,99*x]])]
Does this take the same computational time as...
function 5 = head ([snd pair | pair <- (zip [0..] [sortBy compare [5*5,3-5,99*5]])])
: (maximum ([snd pair | pair <- (zip [0..] [sortBy compare [5*5,3-5,99*5]])])
: minimum ([snd pair | pair <- (zip [0..] [sortBy compare [5*5,3-5,99*5]])]))
i.e. it forms the list from scratch three times throughout the function, even though the result would always be the same.
Or does it calculate it once, and use that value whenever the function is called?
I don't know quite what it would look like otherwise, but as a bit of a muddle of pseudocode and Haskell, I imagine it would go something like this.
function 5...
-- First step, Calculate myList
MyList = [snd pair | pair <- (zip [0..] [sortBy compare [5*5,3-5,99*5]])]
= [-2,25,495]
--Second step, calculate function using myList = [-2,25,495]
function 5 = head (myList) : (maximum (myList) : minimum (myList))
= head [-2,25,495] : maximum [-2,25,495] : minimum [-2,25,495]
= -2 : (495 : -2)
= [-2,495,-2]
I hope it's not too difficult to understand what I am trying to ask here.
Any assistance would be much appreciated, thanks!
The Haskell report does not say how it is evaluated: it merely specifies what the result is.
However, GHC will calculate such list only once. This can have a positive effect on peformance if the list is expensive to produce, since it will be produced only once. Mind that, in some cases, it can also have a negative effect on performance: for instance, (silly example)
let bigList = [1..1000000]
in foldl' (+) 0 bigList + foldl' (-) 0 bigList
will keep the large list in memory until both folds are computed. Instead,
foldl' (+) 0 [1..1000000] + foldl' (-) 0 [1..1000000]
can run in constant space, since the list elements can be garbage collected as soon as they are produced.
For instance, using a 50M list, the first makes GHCi spike to 2.5GB resident memory, and then to return to 100MB. The second has no noticeable effect.