This question already has answers here:
Finite comprehension of an infinite list
(3 answers)
How to filter an infinite list in Haskell [duplicate]
(4 answers)
Closed 4 years ago.
I thought this :
[i | i <- [1..], i < 5]
would produce
[1, 2, 3, 4]
just like
take 4 [i | i <- [1..]]
A finite length list.
But it doesn't, it seems to be infinite because any attempt to treat it as a finite list just causes hang (ghci).
I am not sure how to understand this exactly. Is it some kind of infinite generator which simply produces nothing after the fourth item but never stops?
Basically the code keeps generating new items because it doesn't know they can never satisfy the criterion?
You literally told the program to check every element of the infinite list and include only the ones that are less than 5. As you say, the compiler doesn’t realize that no remaining element of the list will ever satisfy the condition. Nor could it, even in theory, create such a proof at runtime if passed an arbitrary list. It just does what you said, and keeps checking every element.
This is not necessarily a bug if the program does not try to evaluate xs in the result 1:2:3:4:xs, due to lazy evaluation. Taking the head should work just fine. If you tell it to find the length of the list or something like that, though, it’s an infinite loop.
One way to do what you (probably?) want is takeWhile, which stops when the condition is no longer true.
Related
I would like to know how I can turn a function to work with infinite list?
For example, I have a function to revert a list of lists.
innerReverse [[1,2,3]] will return [[3,2,1]]. However, when I tried take 10 $ innerReverse [[1..]] It basically runs into an infinite loop.
When I do innerReverse [(take 10 [1..])] It gives the result: [[10,9,8,7,6,5,4,3,2,1]]
Haskell is a lazy language, which means that evaluations are only performed right before the result is actually used. That's what makes it possible for Haskell to have infinite lists; only the portions of the list that you're accessed so far are actually stored in memory.
The concept of an infinite list makes what you're trying to do impossible. In the list [1..] the first element is 1. What's the last element? The answer is that that's a trick question; there is no concept of the "end" of an infinite list. Similarly, what is the first element of the reverse of [1..]? Again, it's a trick question. The last element is 1, but the list would have no beginning.
The reverse of [1..] is not [10,9,8,7,6,5,4,3,2,1]. The reverse of the latter is [1,2,3,4,5,6,7,8,9,10], not [1..].
I am reading page 69 of Haskell School of Expression and I am not sure that I got the evalution of rev [1:2:3:4] right.
Hudak does not explain the evalution(rewriting) order in detail in his book for reverse.
Could someone please either confirm that my guess (shown in the attached picture) is correct or if not correct then point out what I got wrong. I believe that it is correct but I am not 100% sure, this is the reason for asking.
So the question is:
when I evaluate one step of reverse then aftes the evaluation (i.e. rewriting) the result should be surrounded by parenthesis, right?
If I understand correctly, these unlucky appearance of parentheseses is the reason for the poor (read quadratic) time complexity of reverse. In this example 6 steps are spent in total on list appending in order to reverse a 4 element list.
Yes, nested, left-associative calls to append (in Haskell, goes by the names (++) and (<>)) generates poor performance of singly-linked lists.
There are several solutions to this problem, since it's been known about for 30 or 40 years, at least. I believe the library version of reverse uses an accumulator to achieve linear complexity rather than quadratic, but it's still not something you want to call frequently on lists.
I would like to know if there is a difference between these to definitions.
[(x,y)| x<-[1..10000], x=2000,y<-[1..100], odd y]
[(x,y)| x<-[1..10000],y<-[1..100], x=2000, odd y]
Both will generate same list of tuples.
But if our compiler doesn't do any optimization.
How can i find out which one is faster.
In both case x<-[1..10000] will give us a list from [1,2.. 20000] since x==2000.
In what order will the y value be evaluated?
Things are executed left-to-right. Think of it as nested loops. So in the first one the test of x is executed 10000 times, and in the second it's executed 1000000 times.
Moving the condition outwards to speed up the execution is called "filter promotion"; a term coined by David Turner (ca 1980).
I need a function for deleting elements on nth position in starting list and all sublists. I don't need a working code, i just need any advice.
Asking for advice and not the final solution is laudable. I'll try to explain it to you.
Singly linked lists lend themself to being recursively processed from front to end. You have cheap operations to get the first element of a list, its rest, and to build a list by putting a new element at the front. One simple recursion scheme would be: Take the first element from the list, do something with it, then put it at the front of the result of repeating the whole process with the rest of the list. This repetition of the process for successive elements and rests is the recursive part. If you have an empty input list, there is nothing to do, and the empty list is returned, thus ending the processing. This is your base case, anchor, or whatever you want to call it. Remember: Recursive case, base case, check – you need both.
(Because of Lisp's evaluation rules, to actually put your processed element before the processed rest, it must be remembered until the rest is actually processed, since the operation for building lists evaluates both of its arguments before it returns the new list. These intermediate results will be kept on the stack, which might be a problem for big lists. There are methods that avoid this, but we will keep it simple here.)
Now, you're actually asking not only for simple lists, but for trees. Conveniently, that tree is represented as a nested list, so generally the above still applies, except a little complication: You will have to check whether the element you want to process is itself a branch, i.e. a list. If it is, the whole process must be done on that branch, too.
That's basically it. Now, to remove an element from a tree, your operation is just to check if your element matches and, if yes, dropping it. In more detail:
To remove an element from an empty list, just return an empty list.
If the first element is itself a list, return a list built from the first element with all matches removed as its first, and the rest with all matches removed as its rest.
If its first element matches, return the rest of the list with all
matching elements removed. (Notice that something gets "dropped" here.)
Otherwise, return a list built from the first element as its first and the rest of the list with all maching elements removed as its rest.
Take a look at this and try to find your recursive case, the base case, and what deals with walking the nested tree structure. If you understand all of this, the implementation will be easy. If you never really learned all this, and your head is not spinning by now, consider yourself a natural born Lisp programmer. Otherwise, recursion is just a fundamental concept that maybe hard to grasp the first time, but once it clicked, it's like riding a bicycle.
Ed: Somehow missed the "position" part, and misread – even despite the question title. That's what fatigue can do to people.
Anyway, if you want to delete an element in the tree by position, you can let your function take an optional counter argument (or you can use a wrapping function providing it). If you look at the points above, recursing for a new branch would be the place where you reset your counter. The basic recursion scheme stays the same, but instead of the comparing the element itself, you check your counter – if it matches the position you want to remove, drop the element. In every recursive case, you pass your function the incremented counter, except when entering a new branch, where you reset it, i.e. pass 0 for your counter argument. (You could also just return the rest of the list once the element is dropped, making the function more performant, especially for long lists where an element near the beginning is to be deleted, but let's keep it simple here.)
My approach would be the following:
delete the nth element in the top-level list
recursively delete the nth element in each sublist from the result of #1
I'd implement it this like:
(defun (del n l)
(defun (del-top-level n l)
...) ; return l but with nth gone
(mapcar #'(lambda (l) (if (not (listp l)) l (del n l)))
(del-top-level n l)))
You'd need to implement the del-top-level function.
Ok I think I see what you need.
You should need two functions
The entry function will just call a helper function like (DeleteHelper position position myList)
DeleteHelper will recursively call itself and optionally include the current element of the list if the current position is not 0. Such as (cons (car myList) (DeleteHelper (- position 1) originalPosition (cdr myList))
If DeleteHelper encounters a list, recursively traverse the list with a position reset to the original incoming position. Such as (cons (DeleteHelper originalPosition originalPosition (car myList)) (DeleteHelper (- position 1) originalPosition (cdr myList)))
Also keep in mind the base case (I guess return an empty list once you traverse a whole list).
This should get you in the right direction. It has also been a few years since I wrote any Lisp so my syntax might be a bit off.
In reading Haskell-related stuff I sometimes come across the expression “tying the knot”, I think I understand what it does, but not how.
So, are there any good, basic, and simple to understand explanations of this concept?
Tying the knot is a solution to the problem of circular data structures. In imperative languages you construct a circular structure by first creating a non-circular structure, and then going back and fixing up the pointers to add the circularity.
Say you wanted a two-element circular list with the elements "0" and "1". It would seem impossible to construct because if you create the "1" node and then create the "0" node to point at it, you cannot then go back and fix up the "1" node to point back at the "0" node. So you have a chicken-and-egg situation where both nodes need to exist before either can be created.
Here is how you do it in Haskell. Consider the following value:
alternates = x where
x = 0 : y
y = 1 : x
In a non-lazy language this will be an infinite loop because of the unterminated recursion. But in Haskell lazy evaluation does the Right Thing: it generates a two-element circular list.
To see how it works in practice, think about what happens at run-time. The usual "thunk" implementation of lazy evaluation represents an unevaluated expression as a data structure containing a function pointer plus the arguments to be passed to the function. When this is evaluated the thunk is replaced by the actual value so that future references don't have to call the function again.
When you take the first element of the list 'x' is evaluated down to a value (0, &y), where the "&y" bit is a pointer to the value of 'y'. Since 'y' has not been evaluated this is currently a thunk. When you take the second element of the list the computer follows the link from x to this thunk and evaluates it. It evaluates to (1, &x), or in other words a pointer back to the original 'x' value. So you now have a circular list sitting in memory. The programmer doesn't need to fix up the back-pointers because the lazy evaluation mechanism does it for you.
It's not quite what you asked for, and it's not directly related to Haskell, but Bruce McAdam's paper That About Wraps It Up goes into this topic in substantial breadth and depth. Bruce's basic idea is to use an explicit knot-tying operator called WRAP instead of the implicit knot-tying that is done automatically in Haskell, OCaml, and some other languages. The paper has lots of entertaining examples, and if you are interested in knot-tying I think you will come away with a much better feel for the process.