How to find whether a sequence is increasing? - functional-programming

It's a fragment of a larger task, but I'm really struggling with this. Resources for scheme/lisp are a lot more limited than C, Java, and Python.
If I pass in a var list1 that contains a list of numbers, how can I tell whether the list is in monotonically increasing order or not?

If a list has less than two elements, then we'll say 'yes.'
If a list has two or more elements, then we'll say 'no' if the first is larger than the second, otherwise recurse on the tail of the list.

(define (monotonically-increasing? lst)
(apply < lst))
Or, if you want monotonically-non-decreasing:
(define (monotonically-non-decreasing? lst)
(apply <= lst))
Yes, it's really as simple as that. Totally O(n), and no manual recursion required.
Bonus: For good measure:
(define (sum lst)
(apply + lst))
:-P

If efficiency is not an issue, you can do this:
(equal? list1 (sort list1 <=))
That's an O(n log n) solution, because of the sorting. For an optimal solution, simply compare each element with the next one and test if the current element is less than or equal to the next one, being careful with the last element (which doesn't have a next element). That'll yield an O(n) solution.
This is the general idea of what needs to be done, written in a functional style. Still not the fastest way to write the solution, but at least it's O(n) and very short; you can use it as a basis for writing a simpler solution from scratch:
(define (increasing? lst)
(andmap <=
lst
(append (cdr lst) '(+inf.0))))
The above checks for each number in lst if it's less than or equal to the next number. The andmap procedure tests if the <= condition holds for all pairs of elements in two lists. The first list is the one passed as a parameter, the second list is the same list, but shifted one position to the right, with the positive infinite value added at the end to preserve the same size in both lists - it works for the last element because any number will be smaller than infinite. For example, with this list:
(increasing? '(1 2 3))
The above procedure call will check that (<= 1 2) and (<= 2 3) and (<= 3 +inf.0), because all conditions evaluate to #t the whole procedure returns #t. If just one of the conditions had failed, the whole procedure would have returned #f.

Related

Finding duplicate elements in a Scheme List using recursion

I'm trying to create a function that will check a list of numbers for duplicates and return either #t or #f. I can only use car, cdr and conditionals, no cons.
This is what I have so far but it's giving me the error "car: contract violation expected: pair? given: #f"
(define (dups a)
(if (null? a)
#f
(if (= (car a)(car(dups(cdr a))))
#t
(dups (cdr))
)
)
)
I'm new to both scheme and recursion, any help/advice would be greatly appreciated.
Your second if doesn't make much sense. I'm assuming you wanted to check whether (car a) appears somewhere further down the list, but (car (dups (cdr a))) doesn't give you that. Also, (car (dups ...)) is a type-issue since dups will return a boolean instead of a list, and car is expecting a list (or actually, a pair, which is what lists are composed of).
What you need is a second function to call in the test of that second if. That function takes an element and a list and searches for that element in the list. Of course, if you're allowed, use find, otherwise implement some sort of my-find - it's quite simple and similar to your dups function.

How to understand clojure's lazy-seq

I'm trying to understand clojure's lazy-seq operator, and the concept of lazy evaluation in general. I know the basic idea behind the concept: Evaluation of an expression is delayed until the value is needed.
In general, this is achievable in two ways:
at compile time using macros or special forms;
at runtime using lambda functions
With lazy evaluation techniques, it is possible to construct infinite data structures that are evaluated as consumed. These infinite sequences utilizes lambdas, closures and recursion. In clojure, these infinite data structures are generated using lazy-seq and cons forms.
I want to understand how lazy-seq does it's magic. I know it is actually a macro. Consider the following example.
(defn rep [n]
(lazy-seq (cons n (rep n))))
Here, the rep function returns a lazily-evaluated sequence of type LazySeq, which now can be transformed and consumed (thus evaluated) using the sequence API. This API provides functions take, map, filter and reduce.
In the expanded form, we can see how lambda is utilized to store the recipe for the cell without evaluating it immediately.
(defn rep [n]
(new clojure.lang.LazySeq (fn* [] (cons n (rep n)))))
But how does the sequence API actually work with LazySeq?
What actually happens in the following expression?
(reduce + (take 3 (map inc (rep 5))))
How is the intermediate operation map applied to the sequence,
how does take limit the sequence and
how does terminal operation reduce evaluate the sequence?
Also, how do these functions work with either a Vector or a LazySeq?
Also, is it possible to generate nested infinite data structures?: list containing lists, containing lists, containing lists... going infinitely wide and deep, evaluated as consumed with the sequence API?
And last question, is there any practical difference between this
(defn rep [n]
(lazy-seq (cons n (rep n))))
and this?
(defn rep [n]
(cons n (lazy-seq (rep n))))
That's a lot of questions!
How does the seq API actually works with LazySeq?
If you take a look at LazySeq's class source code you will notice that it implements ISeq interface providing methods like first, more and next.
Functions like map, take and filter are built using lazy-seq (they produce lazy sequences) and first and rest (which in turn uses more) and that's how they can work with lazy seq as their input collection - by using first and more implementations of LazySeq class.
What actually happens in the following expression?
(reduce + (take 3 (map inc (rep 5))))
The key is to look how LazySeq.first works. It will invoke the wrapped function to obtain and memoize the result. In your case it will be the following code:
(cons n (rep n))
Thus it will be a cons cell with n as its value and another LazySeq instance (result of a recursive call to rep) as its rest part. It will become the realised value of this LazySeq object and first will return the value of the cached cons cell.
When you call more on it, it will in the same way ensure that the value of the particular LazySeq object is realised (or reused memoized value) and call more on it (in this case more on the cons cell containing another LazySeq object).
Once you obtain another instance of LazySeq object with more the story repeats when you call first on it.
map and take will create another lazy-seq that will call first and more of the collection passed as their argument (just another lazy seq) so it will be similar story. The difference will be only in how the values passed to cons are generated (e.g. calling f to a value obtained by first invoked on the LazySeq value mapped over in map instead of a raw value like n in your rep function).
With reduce it's a bit simpler as it will use loop with first and more to iterate over the input lazy seq and apply the reducing function to produce the final result.
As the actual implementation looks like for map and take I encourage you to check their source code - it's quite easy to follow.
How seq API can works with different collection types (e.g. lazy seq and persistent vector)?
As mentioned above, map, take and other functions work in terms of first and rest (reminder - rest is implemented on top of more). Thus we need to explain how first and rest/more can work with different collection types: they check if the collection implements ISeq (and then it implement those functions directly) or they try to create a seq view of the collection and coll its implementation of first and more.
Is it possible to generate nested infinite data structures?
It's definitely possible but I am not sure what the exact data shape you would like to get. Do you mean getting a lazy seq which generates another sequence as it's value (instead of a single value like n in your rep) but returns it as a flat sequence?
(defn nested-cons [n]
(lazy-seq (cons (repeat n n) (nested-cons (inc n)))))
(take 3 (nested-cons 1))
;; => ((1) (2 2) (3 3 3))
that would rather return (1 2 2 3 3 3)?
For such cases you might use concat instead of cons which creates a lazy sequence of two or more sequences:
(defn nested-concat [n]
(lazy-seq (concat (repeat n n) (nested-concat (inc n)))))
(take 6 (nested-concat 1))
;; => (1 2 2 3 3 3)
Is there any practical difference with this
(defn rep [n]
(lazy-seq (cons n (rep n))))
and this?
(defn rep [n]
(cons n (lazy-seq (rep n))))
In this particular case not really. But in the case where a cons cell doesn't wrap a raw value but a result of a function call to calculate it, the latter form is not fully lazy. For example:
(defn calculate-sth [n]
(println "Calculating" n)
n)
(defn rep1 [n]
(lazy-seq (cons (calculate-sth n) (rep1 (inc n)))))
(defn rep2 [n]
(cons (calculate-sth n) (lazy-seq (rep2 (inc n)))))
(take 0 (rep1 1))
;; => ()
(take 0 (rep2 1))
;; Prints: Calculating 1
;; => ()
Thus the latter form will evaluate its first element even if you might not need it.

Scheme infinite recursion

I'm writing my own version of quicksort, and something is causing an infinite recursion that I can't track down for some reason.
(define (quicksort-test list)
(cond
((null? list) '())
(else
(appending (quicksort-test (less-than-builder list (car list)))
(quicksort-test (geq-builder list (car list)))))))
Appending is a helper function which just appends one list onto another, and less-than-builder and geq-builder are helper functions which take a list and a pivot as inputs, and then build a list of everything less than the pivot and a list of everything greater than or equal to the pivot, respectively. I think the problem is in my else statement, though I can't see why for some reason, maybe due to a fried brain.
Building a list of every element that's greater than or equal to a pivot element will never return an empty list, it will just get down to a single element and keep calling itself over and over again because a list with a single element is always greater than or equal to itself.
You need to remove the pivot element – recurse on (cdr list) – and put it back in the middle afterwards.
Credit goes to molbdnilo and Eddie V for solving this problem in the comments

member? function on infinite lists

I implemented a member? function in clojure as follows:
(defn member? [item seq]
(cond (empty? seq) false
(= item (first seq)) true
:else (recur item (rest seq))))
Unfortunately this doesn't work with infinite lists. Does anybody know of a way to implement it in order to be able to get:
(member? 3 (range)) -> true
Your implementation behaves correctly for an infinite input sequence. It does not terminate until an element has been found because the (empty? seq) case never falls.
Consider searching for something in an infinite space. When is it a good time to say it isn't there? There is no reliable way to tell. Limit the space you are searching in, e. g.:
(member? 3 (take 10 (range)))
You can't. I mean, at all.
In order to make sure there is no certain element you need to traverse the entire collection. Then and only then you can guarantee it's not there.
In some cases, such as your example, input sequence is ascending, i. e. every element of your sequence is less than its successive element. You can leverage that and make your sequence finite using take-while:
(member? 3 # is 3 a member of
(take-while # a sequence of elements
#(<= % 3) # up to 3 inclusively
range)) # from range
For me, your code already works: (member? 3 (range)) returns true.
But what is the point of checking for the existence of a value in an infinite sequence? It will either return true or it will never return.

SICP 2.64 order of growth of recursive procedure

I am self-studyinig SICP and having a hard time finding order of growth of recursive functions.
The following procedure list->tree converts an ordered list to a balanced search tree:
(define (list->tree elements)
(car (partial-tree elements (length elements))))
(define (partial-tree elts n)
(if (= n 0)
(cons '() elts)
(let ((left-size (quotient (- n 1) 2)))
(let ((left-result (partial-tree elts left-size)))
(let ((left-tree (car left-result))
(non-left-elts (cdr left-result))
(right-size (- n (+ left-size 1))))
(let ((this-entry (car non-left-elts))
(right-result (partial-tree (cdr non-left-elts)
right-size)))
(let ((right-tree (car right-result))
(remaining-elts (cdr right-result)))
(cons (make-tree this-entry left-tree right-tree)
remaining-elts))))))))
I have been looking at the solution online, and the following website I believe offers the best solution but I have trouble making sense of it:
jots-jottings.blogspot.com/2011/12/sicp-exercise-264-constructing-balanced.html
My understanding is that the procedure 'partial-tree' repeatedly calls three argument each time it is called - 'this-entry', 'left-tree', and 'right-tree' respectively. (and 'remaining-elts' only when it is necessary - either in very first 'partial-tree' call or whenever 'non-left-elts' is called)
this-entry calls : car, cdr, and cdr(left-result)
left-entry calls : car, cdr, and itself with its length halved each step
right-entry calls: car, itself with cdr(cdr(left-result)) as argument and length halved
'left-entry' would have base 2 log(n) steps, and all three argument calls 'left-entry' separately.
so it would have Ternary-tree-like structure and the total number of steps I thought would be similar to 3^log(n). but the solution says it only uses each index 1..n only once. But doesn't 'this-entry' for example reduce same index at every node separate to 'right-entry'?
I am confused..
Further, in part (a) the solution website states:
"in the non-terminating case partial-tree first calculates the number
of elements that should go into the left sub-tree of a balanced binary
tree of size n, then invokes partial-tree with the elements and that
value which both produces such a sub-tree and the list of elements not
in that sub-tree. It then takes the head of the unused elements as the
value for the current node"
I believe the procedure does this-entry before left-tree. Why am I wrong?
This is my very first book on CS and I have yet to come across Master Theorem.
It is mentioned in some solutions but hopefully I should be able to do the question without using it.
Thank you for reading and I look forward to your kind reply,
Chris
You need to understand how let forms work. In
(let ((left-tree (car left-result))
(non-left-elts (cdr left-result))
left-tree does not "call" anything. It is created as a new lexical variable, and assigned the value of (car left-result). The parentheses around it are just for grouping together the elements describing one variable introduced by a let form: the variable's name and its value:
(let ( ( left-tree (car left-result) )
;; ^^ ^^
( non-left-elts (cdr left-result) )
;; ^^ ^^
Here's how to understand how the recursive procedure works: don't.
Just don't try to understand how it works; instead analyze what it does, assuming that it does (for the smaller cases) what it's supposed to do.
Here, (partial-tree elts n) receives two arguments: the list of elements (to be put into tree, presumably) and the list's length. It returns
(cons (make-tree this-entry left-tree right-tree)
remaining-elts)
a cons pair of a tree - the result of conversion, and the remaining elements, which are supposed to be none left, in the topmost call, if the length argument was correct.
Now that we know what it's supposed to do, we look inside it. And indeed assuming the above what it does makes total sense: halve the number of elements, process the list, get the tree and the remaining list back (non-empty now), and then process what's left.
The this-entry is not a tree - it is an element that is housed in a tree's node:
(let ((this-entry (car non-left-elts))
Setting
(right-size (- n (+ left-size 1))
means that n == right-size + 1 + left-size. That's 1 element that goes into the node itself, the this-entry element.
And since each element goes directly into its node, once, the total running time of this algorithm is linear in the number of elements in the input list, with logarithmic stack space use.

Resources