• Due: 5pm Saturday 20 February. (But you should try to complete as much of it as possible before 5pm Fri 19 Februrary, while help is easily available.)
• Notes:
• This is a long assignment. Start soon!
• You should be able to do Problems 1 and 2 now.
• Problem 2 involves reading a paper that will be somewhat challenging for many students. Start reading the paper right away.
• You might be able to do some of Problems 3, 4, and 5 now, but will be able to do them all after the Tue. Feb 16 class.
• The problems needn’t be done in order. Feel free to jump around.
• The problem set is worth 125 points.
• We’re asking you to keep track of the time estimates for each problem/subproblem.
• Submission:
• In the yourFullName CS251 Spring 2016 Folder that you created for PS1, create a Google Doc named yourFullName CS251 PS3.
• For each problem and subproblem, please indicate at the beginning of each writeup approximately how long that problem took you to solve and write up.
• For Problems 1 and 2, include all answers in your PS3 google doc. Please format your evaluation derivations in Problem 1 so that they’re easy to read. Format the derivation using the fixed-width Courier New font (can use a small font size if that helps).
• For Problems 3 through 5:
• Copy the contents of `yourAccountName-ps3-functions.rkt` to the Google Doc. Format the definitions using the fixed-width Courier New font (can use a small font size if that helps).
• Drop a copy of your `yourAccountName-ps3-functions.rkt` in your `~/cs251/drop/ps03` drop folder on cs.wellesley.edu.

## 1. Wacky Lists (20 points)

This problem shows that functions can be used to implement data structures like pairs and lists. Consider the following alternatives to Racket’s usual built-in `cons`, `car`, `cdr`, `null`, and `null?`:

``````    (define kons (λ (x y) (λ (f) (f #f x y))))

(define kar (λ (k) (k (λ (b f s) f))))

(define kdr (λ (k) (k (λ (b f s) s))))

(define knull (λ (f) (f #t 0 0)))

(define knull? (λ (k) (k (λ (b f s) b))))``````
1. (2 points) Use the small-step substitution model (i.e., using ⇒) to show the evaluation of the value bound to the name `p` by the following declaration:

`` (define p (kons 3 4))``
2. (12 points) Use the small-step substitution model (i.e., using ⇒) to show the evalulation of each of the following expressions.
• `(kar p)`
• `(kdr p)`
• `(knull? p)`
• `(knull? knull)`
3. (3 points) The following `sum-to` function uses helper functions `sum` and `down-from` defined in terms of the list-like entities involving `kons` and friends. Does it actually calculate the sum of the integers from 1 to `n` (inclusive)? Explain why or why not.

`````` (define (sum-to n)
(sum (down-from n)))

(define (sum nums)
(if (knull? nums)
0
(+ (kar nums) (sum (kdr nums))))) ; sum was accidentally ksum before and has been corrected

(define (down-from n)
(if (<= n 0)
knull
(kons n (down-from (- n 1)))))``````
4. (3 points) Can we replace all instances of `cons`/`car`/`cdr`/`null`/`null?` in Racket by `kons`/`kar`/`kdr`/`knull`/`knull?`? Are there any ways in which `kons`/`kar`/`kdr`/`knull`/`knull?` do not behave like `cons`/`car`/`cdr`/`null`/`null?`

## 2. Backus’s Paper (30 points)

This problem is about John Backus’s 1977 Turing Award Lecture: Can Programming be Liberated from the von Neumann Style? A Functional Style and its Algebra of Programs. His paper can be found here.

You should begin this problem by reading Sections 1–11 and 15–16 of this paper. (Although Sections 12–14 are very interesting, they require more time than I want you to spend on this problem.)

Section 11.2 introduces the details of the FP language. Backus uses many notations that may be unfamiliar to you. For example:

• p1 → e1; … ; pn → en; en+1 is similar to the Racket expression `(if `p1e1` (if `pnenen+1`)``)`.

• ⟨e1, …, en denotes the sequence of the n values of the expressions e1, … en. φ denotes the empty sequence. Because FP is dynamically typed, such sequences can represent both tuples and lists from Python and OCaml.

• The symbol ⊥ (pronounced “bottom”) denotes the value of an expression that doesn’t terminate (i.e., it loops infinitely) or terminates with an error.

• If f is a function and x is an object (atom or sequence of objects), then f : x denotes the result of applying f to x.

• [f1, …, fn] is a functional form denoting a sequence of n functions, f1 through fn. The application rule for this functional form is [f1, …, fn] : x = ⟨f1 : x, … , fn : x⟩ — i.e., the result of applying a sequence of n functions to an object x is an n-element sequence consisting of the results of applying each of the functions in the function sequence to x.

Consult Lyn if you have trouble understanding Backus’s notation.

1. (2 points) One of the reasons this paper is well-known is that in it Backus coined the term “von Neumann bottleneck”. Describe what this is and its relevance to the paper.

2. (2 points) Many programming languages have at least two syntactic categories: expressions and statements. Backus claims that expressions are good but statements are bad. Explain his claim.

3. (3 points) In Sections 6, 7, and 9 of the paper, Backus discusses three problems/defects with von Neumann languages. Summarize them.

4. (3 points) What are applicative languages and how do they address the three problems/defects mentioned by Backus for von Neumann languages?

5. (2 points) The FP language Backus introduces in Section 11 does not support abstraction expressions like Racket’s `lambda`. Why did Backus make this decision in FP?

6. (6 points) Backus wrote this paper long before the development of Java and Python. Based on his paper, how do you think he would evaluate these two languages?

7. (12 points) Consider the following FP definition:

``Def F ≡ α/+ ◦ αα× ◦ αdistl ◦ distr ◦ [id, id]``

What is the value of F⟨2, 3, 5⟩? Show the evaluation of this expression in algebra-like steps.

## 3. Higher-order List Functions (43 points)

In this and the following problems you will revisit some functions from PS2 Problem 4, as well as some new ones. However, rather than expressing them as recursions, you will express them in terms of higher-order-list-operators.

Notes:

• For problems 3 through 5, you should use Dr. Racket to create a single file named `yourAccountName-ps3-functions.rkt` that contains all the functions (including helper functions) that you define for this problem.

• In your definitions, you are not allowed to use recursion anywhere. (The one exception is the `inserts-rec` helper function you are given in Problem 3l.)

• In your definitions, unless otherwise instructed, you should not introduce any new named helper functions, but you can (1) liberally use anonymous functions and (2) use functions you defined in previous parts in later parts.

1. (3 points) Using Racket’s `map`, define a function `map-remainder` that takes two arguments (an integer `divisor` and a list `ints` of integers) and returns an integer list the same length as `ints` in which every element is remainder of dividing the corresponding element of `ints` by `divisor`.

`````` > (map-remainder 2 (list 16 23 42 57 64 100))
'(0 1 0 1 0 0)
> (map-remainder 3 (list 16 23 42 57 64 100))
'(1 2 0 0 1 1)
> (map-remainder 5 (list 16 23 42 57 64 100))
'(1 3 2 2 4 0)
> (map-remainder 17 (list 16 23 42 57 64 100))
'(16 6 8 6 13 15)``````
2. (3 points) Using Racket’s `filter`, define a function `filter-divisible-by` that takes two arguments (an integer `divisor` and a list `ints` of integers) and returns a new integer list containing all the elements of `ints` that are divisible by `divisor`. Use `divisible-by?` from PS2 Problem 4 to determine divisibility.

`````` > (filter-divisible-by 2 (list 16 23 42 57 64 100))
'(16 42 64 100)
> (filter-divisible-by 3 (list 16 23 42 57 64 100))
'(42 57)
> (filter-divisible-by 4 (list 16 23 42 57 64 100))
'(16 64 100)
> (filter-divisible-by 5 (list 16 23 42 57 64 100))
'(100)
> (filter-divisible-by 17 (list 16 23 42 57 64 100))
'()``````
3. (3 points) Using Racket’s `foldr`, define a function `contains-multiple?` that takes an integer `m` and a list of integers `ns` that returns `#t` if `m` evenly divides at least one element of the integer list `ns`; otherwise it returns `#f`. Use `divisible-by?` from above to determine divisibility.

`````` > (contains-multiple? 5 (list 8 10 14))
#t
> (contains-multiple? 3 (list 8 10 14))
#f
> (contains-multiple? 5 null)
#f``````
4. (3 points) Using Racket’s `foldr`, define a function `all-contain-multiple?` that takes an integer `n` and a list of lists of integers `nss` (pronounced “enziz”) and returns `#t` if each list of integers in `nss` contains at least one integer that is a multiple of `n`; otherwise it returns `#f`. Use `contains-multiple?` in your definition of `all-contain-multiple?`.

`````` > (all-contain-multiple? 5 (list (list 17 10 2) (list 25) (list 3 8 5)))
#t
> (all-contain-multiple? 2 (list (list 17 10 2) (list 25) (list 3 8 5)))
#f
> (all-contain-multiple? 3 null)
#t ; said to be "vacuously true"; there is no counterexample!``````
5. (3 points) Using Racket’s `foldr`, define a function `snoc` that takes list `ys` and a value `x`, and returns the new list that results from adding `x` to the end of `ys`.

`````` > (snoc (list 7 2 5) 4)
'(7 2 5 4)
> (snoc (list) 4)
'(4)``````
6. (3 points) Using Racket’s `foldr`, define a function `my-append` that takes two lists, `xs` and `ys`, and returns the new list that contains all the elements of `xs` followed by all the elements of `ys`.

`````` > (my-append (list 7 2 5) (list 4 6))
'(7 2 5 4 6)
> (my-append (list) (list 4 6))
'(4 6)
> (my-append (list 7 2 5) (list))
'(7 2 5)
> (my-append (list) (list))
'()``````

Note: You may not use Racket’s `append` in your definition.

7. (3 points) Using Racket’s `foldr`, define a function `append-all` that takes a list of lists `xss` and returns a new list that contains all the elements of the sublists of `xss` in their relative order.

`````` > (append-all (list (list 1 2) (list 3) (list 4 5 6)))
'(1 2 3 4 5 6)
> (append-all (list (list 1 2) (list 3)))
'(1 2 3)
> (append-all (list (list 1 2)))
'(1 2)
> (append-all (list))
'()
> (append-all (list (list (list 1 2) (list 3 4 5)) (list (list 6)) (list (list 7 8) (list) (list 9))))
'((1 2) (3 4 5) (6) (7 8) () (9))``````

Note: You may use `append` or `my-append` in your definition.

8. (3 points) Using Racket’s `map`, define a function `map-cons` that takes any value `x` and an n-element list `ys` and returns an n-element list of all pairs `'(x . y)` where `y` ranges over the elements of `ys`. The pair `'(x . y)` should have the same relative position in the resulting list as `y` has in `ys`.

`````` > (map-cons 17 (list 8 5 42 23))
'((17 . 8) (17 . 5) (17 . 42) (17 . 23))
> (map-cons 3 (list (list 1 6 2) (list 4 5) (list) (list 9 6 8 7)))
'((3 1 6 2) (3 4 5) (3) (3 9 6 8 7))
> (map-cons 42 null)
'()``````
9. (5 points) Using Racket’s `foldr`, define a function `my-cartesian-product` that takes two lists `xs` and `ys` and returns a list of all pairs `'(x . y)` where `x` ranges over the elements of `xs` and `y` ranges over the elements of `ys`. The pairs should be sorted first by the `x` entry (relative to the order in `xs`) and then by the `y` entry (relative to the order in `ys`).

`````` > (my-cartesian-product (list 1 2) (list "a" "b" "c")) ; yes, Racket has string values
'((1 . "a") (1 . "b") (1 . "c") (2 . "a") (2 . "b") (2 . "c"))
> (my-cartesian-product (list 2 1) (list "a" "b" "c"))
'((2 . "a") (2 . "b") (2 . "c") (1 . "a") (1 . "b") (1 . "c"))
> (my-cartesian-product (list "c" "b" "a") (list 2 1))
'(("c" . 2) ("c" . 1) ("b" . 2) ("b" . 1) ("a" . 2) ("a" . 1))
> (my-cartesian-product (list "a" "b") (list 2 1))
'(("a" . 2) ("a" . 1) ("b" . 2) ("b" . 1))
> (my-cartesian-product (list 1) (list "a"))
'((1 . "a"))
> (my-cartesian-product null (list "a" "b" "c"))
'()``````

Note: You may use `map-cons` and `append` or `my-append` in your definition.

10. (4 points) Using Racket’s `foldr`, define a function `my-reverse` that takes a list `xs` and returns a new list whose elements are the elements of `xs` in reverse order. You may not use the built-in `reverse` function.

``````> (my-reverse (list 1 2 3 4))
'(4 3 2 1)
> (my-reverse (list 1))
'(1)
> (my-reverse (list))
'()``````

Note:

• We ask you to name your function `my-reverse` because Racket already provides the same function named `reverse` (which you cannot use, of course).
• You may use `snoc` or `append` or `my-append` in your definition.
11. (5 points) Assume that the elements of a list are indexed starting with 0. Using Racket’s `foldr`, define a function `alts` that takes a list `xs` and returns a two-element list of of lists, the first of which has all the even-indexed elements (in the same relative order as in `xs`) and the second of which has all the even-indexed elements (in the same relative order as in `xs`).

``````> (alts (list 7 5 4 6 9 2 8 3))
'((7 4 9 8) (5 6 2 3))
> (alts (list 5 4 6 9 2 8 3))
'((5 6 2 3) (4 9 8))
> (alts (list 4 6 9 2 8 3))
'((4 9 8) (6 2 3))
> (alts (list 3))
'((3) ())
> (alts null)
'(() ())``````

Note: There is no need to treat even-length and odd-length cases differently, nor is there any need to treat the singleton list specially.

12. (5 points) Assume you are supplied with the following recursive version of the `inserts` function from PS2 Problem 4:

``````(define (inserts-rec x ys)
(if (null? ys)
(list (list x))
(cons (cons x ys)
(map-cons (car ys)
(inserts-rec x (cdr ys))))))``````

Using Racket’s `foldr`, define a function `my-permutations` that takes as its single argument a list `xs` of distinct elements (i.e., no duplicates) and returns a list of all the permutations of the elements of `xs`. The order of the permutations does not matter.

``````> (my-permutations null)
'(())
> (my-permutations (list 4))
'((4))
> (my-permutations (list 3 4))
'((3 4) (4 3)) ; order doesn't matter
> (my-permutations (list 2 3 4))
'((2 3 4) (3 2 4) (3 4 2) (2 4 3) (4 2 3) (4 3 2))
> (my-permutations (list 1 2 3 4))
'((1 2 3 4) (2 1 3 4) (2 3 1 4) (2 3 4 1)
(1 3 2 4) (3 1 2 4) (3 2 1 4) (3 2 4 1)
(1 3 4 2) (3 1 4 2) (3 4 1 2) (3 4 2 1)
(1 2 4 3) (2 1 4 3) (2 4 1 3) (2 4 3 1)
(1 4 2 3) (4 1 2 3) (4 2 1 3) (4 2 3 1)
(1 4 3 2) (4 1 3 2) (4 3 1 2) (4 3 2 1))``````

Note: It is helpful to use `append-all`, `map`, and `inserts-rec` in your solution.

## 4. `forall?`, `exists?`, `find`, and `zip` (20 points)

Here are some list-processing functions that are not built in to Racket, but are handy in many situations:

``````(define (forall? pred xs)
(if (null? xs)
#t
(and (pred (car xs))
(forall? pred (cdr xs)))))

(define (exists? pred xs)
(if (null? xs)
#f
(or (pred (car xs))
(exists? pred (cdr xs)))))

(define (find pred not-found xs)
(if (null? xs)
not-found
(if (pred (car xs))
(car xs)
(find pred not-found (cdr xs)))))

(define (zip xs ys)
(if (or (null? xs) (null? ys))
null
(cons (cons (car xs) (car ys))
(zip (cdr xs) (cdr ys)))))``````

`forall?`, `exists?`, and `find` are higher-order list functions involving a predicate.

• `forall?` returns `#t` if the predicate is true on all elements of the list, and otherwise returns `#f`.
• `exists?` returns `#t` if the predicate is true on at least one element of the list, and otherwise returns `#f`.
• `find` returns the first element of the list for which the predicate is true. If there is no such element, it returns the value supplied as the `not-found` argument.

``````  > (forall? (λ (x) (> x 0)) (list 7 2 5 4 6))
#t
> (forall? (λ (x) (> x 0)) (list 7 2 -5 4 6))
#f
> (exists? (λ (x) (< x 0)) (list 7 2 -5 4 6))
#t
> (exists? (λ (x) (< x 0)) (list 7 2 5 4 6))
#f
> (find (λ (x) (< x 0)) #f (list 7 2 -5 4 -6))
-5
> (find (λ (x) (< x 0)) #f (list 7 2 5 4 6))
#f``````

The `zip` function is not higher order, but combines two lists by pairing (using `cons`) the corresponding elements of the two lists. If the lists do not have the same length, `zip` returns a list of pairs whose length is the length of the shorter of the two input lists:

``````    > (zip (list 1 2 3) (list "a" "b" "c"))
'((1 . "a") (2 . "b") (3 . "c"))
> (zip (list 1 2 3 4 5) (list "a" "b" "c"))
'((1 . "a") (2 . "b") (3 . "c"))
> (zip (list 1 2 3) (list "a" "b" "c" "d" "e"))
'((1 . "a") (2 . "b") (3 . "c"))``````
1. (3 points) Using `exists?`, define a function `member?` that determines if an element `x` appears in a list `ys`.

`````` > (member? 4 (list 7 2 5 4 6))
#t
> (member? 3 (list 7 2 5 4 6))
#f
> (member? (list 7 8) (list (list 1 2) (list 3 4 5) (list 6) (list 7 8) (list) (list 9)))
#t
> (member? (list) (list (list 1 2) (list 3 4 5) (list 6) (list 7 8) (list) (list 9)))
#t
> (member? (list 5 6) (list (list 1 2) (list 3 4 5) (list 6) (list 7 8) (list) (list 9)))
#f``````

Note: Use `equal?` to compare the equality of two values.

2. (5 points) Using `forall?` and `exists?`, define a function `all-contain-multiple-alt?` that is an alternative implementation of the `all-contain-multiple?` function from Problem 3.

`````` > (all-contain-multiple-alt? 5 (list (list 17 10 2) (list 25) (list 3 8 5)))
#t
> (all-contain-multiple-alt? 2 (list (list 17 10 2) (list 25) (list 3 8 5)))
#f
> (all-contain-multiple-alt? 3 null)
#t ; said to be "vacuously true"; there is no counterexample!``````

Note: You may use the `divisible_by` function from above, but not the `contains-multiple?` function, and you may not define any new helper functions.

3. (4 points) An association list is a list of pairs that represents a mapping from key to value. Each pair of key and value is represented by a cons cell, with the key in the `car` and the value in the `cdr`. For example, the association list:

`` (list (cons 2 3) (cons 5 1) (cons "mountain" #t))``

maps the key `2` to the value `3`, the key `5` to the value `1`, and the key `"mountain"` to the value `#t`.

Using `find`, define a function `lookup` that takes a key `k` and an association list `as` and returns:

• `#f` if no mapping with key `k` was not found in the list; and
• a cons cell whose `car` is `k` and whose `cdr` is the corresponding value for the shallowest mapping of `k` in the association list.

For example:

`````` > (lookup 1 (list (cons 2 3) (cons 5 1) (cons "mountain" #t)))
#f
> (lookup 5 (list (cons 2 3) (cons 5 1) (cons "mountain" #t)))
'(5 . 1)
> (lookup 5 (list (cons 2 3) (cons 5 1) (cons 5 "river")))
'(5 . 1)
> (lookup (list 3 5) (list (cons (list 3 5) 2) (cons 5 1)))
'((3 5) . 2)``````

Note: Use `equal?` to test for equality of keys. This will support keys more interesting than just simple values.

4. (5 points) Using `forall?` and `zip`, define a function `sorted?` that determines if a list of numbers `ns` is in sorted order from low to high.

`````` > (sorted? (list 7 4 2 5 4 6))
#f
> (sorted? (list 2 3 3 5 6 7))
#t
> (sorted? (list 2))
#t
> (sorted? (list))
#t``````

Note: You will need to have a special case for the empty list.

5. (3 points) It is possible to define alternative versions of `forall?` and `exists?` in terms of `foldr`, as show below.

`````` (define (forall-alt? pred xs)
(foldr (λ (x subres) (and (pred x) subres))
#t
xs))

(define (exists-alt? pred xs)
(foldr (λ (x subres) (or (pred x) subres))
#f
xs))

> (forall-alt? (λ (x) (> x 0)) (list 7 2 5 4 6))
#t
> (forall-alt? (λ (x) (> x 0)) (list 7 2 -5 4 6))
#f
> (exists-alt? (λ (x) (< x 0)) (list 7 2 -5 4 6))
#t
> (exists-alt? (λ (x) (< x 0)) (list 7 2 5 4 6))``````

However, just because it’s possible to define a function in terms of `foldr` does not mean its a good idea. Give a concrete example of a situation in which `forall?` is better than `forall-alt?`.

Note: For this problem, it’s critical to understand that `(and e1 e2)` desugars to `(if e1 e2 #f)`

## 5. `foldr-ternop` (12 points)

Sometimes it is difficult to express a recursive list accumulation in terms of `foldr` because the binary combiner function needs more information from the list than its first element. The following `foldr-ternop` higher-order list function solves this problem by having the combiner function be a ternary (i.e., three-argument) function that takes both the first and rest of the given list in addition to the result of recursively processing the list:

``````(define (foldr-ternop ternop null-value xs)
(if (null? xs)
null-value
(ternop (first xs)
(rest xs)
(foldr-ternop ternop null-value (rest xs)))))``````

In this problem, you will use `foldr-ternop` to implement two list functions that are very challenging to implement in terms of `foldr` (see the extra credit problem below).

1. (6 points) Using `foldr-ternop`, define a function `inserts` that takes a value `x` and an n-element list `ys` and returns an n+1-element list of lists showing all ways to insert a single copy of `x` into `ys`.

`````` > (inserts 3 (list 5 7 1))
'((3 5 7 1) (5 3 7 1) (5 7 3 1) (5 7 1 3))
> (inserts 3 (list 7 1))
'((3 7 1) (7 3 1) ( 7 1 3))
> (inserts 3 (list 1))
'((3 1) (1 3))
> (inserts 3 null)
'((3))
> (inserts 3 (list 5 3 1))
'((3 5 3 1) (5 3 3 1) (5 3 3 1) (5 3 1 3))``````

Notes:

• Your definition should have exactly this pattern:

``````(define (inserts-foldr x ys)
(foldr-ternop {ternary-combiner} {null-value} ys))``````
• You may use `map-cons` in your ternary-combiner function.

2. (6 points) Using `foldr-ternop`, define a function `sorted-alt?` that is an alternative implementation of the `sorted?` function from Problem 4.

`````` > (sorted-alt? (list 7 4 2 5 4 6))
#f
> (sorted-alt? (list 2 3 3 5 6 7))
#t
> (sorted-alt? (list 2))
#t
> (sorted-alt? (list))
#t``````

Note:

• Your definition should have exactly this pattern:

``````(define (sorted-alt? xs)
(foldr-ternop {ternary-combiner} {null-value} xs))``````

## Extra Credit: Using `foldr` to define `inserts` and `sorted?` (20 points)

This problem is optional. You should only attempt it after completing all the other problems.

As noted in Problem 5, it is challenging to define `inserts` and `sorted` in terms of `foldr`, but it turns out that it is stil possible to do this.

1. (8 points) Using `foldr`, define a function `inserts-foldr` that is an alternative implementation of the `inserts` function from Probem 5.

`````` > (inserts-foldr 3 (list 5 7 1))
'((3 5 7 1) (5 3 7 1) (5 7 3 1) (5 7 1 3))
> (inserts-foldr 3 (list 7 1))
'((3 7 1) (7 3 1) ( 7 1 3))
> (inserts-foldr 3 (list 1))
'((3 1) (1 3))
> (inserts-foldr 3 null)
'((3))
> (inserts-foldr 3 (list 5 3 1))
'((3 5 3 1) (5 3 3 1) (5 3 3 1) (5 3 1 3))``````

Note:

• Your definition should have exactly this pattern:

``````(define (inserts-foldr x ys)
(foldr {binary-combiner} {null-value} ys))``````
• You may use `map-cons` in your binary-combiner function.

2. (12 points) Using `foldr`, define a function `sorted-foldr?` that is an alternative implementation of the `sorted?` function from Problem 5.

`````` > (sorted-foldr? (list 7 4 2 5 4 6))
#f
> (sorted-foldr? (list 2 3 3 5 6 7))
#t
> (sorted-foldr? (list 2))
#t
> (sorted-foldr? (list))
#t``````

Note:

• Your definition should have exactly this pattern:

``````(define (inserts-foldr x ys)
(cdr (foldr {binary-combiner} (cons {null-value1} {null-value2}) ys)))``````

The idea is to accumulate a pair of (1) the first element of the rest of the list (or `#f` if there is none) and (2) a boolean indicating whether the rest of the list is sorted.