Sudoku Solver in Scheme? - scheme

We made a matrix library for scheme in class (documentation here:
http://www.cs.indiana.edu/cgi-pub/c211/wombat/docs/c211-matrix.htm
So as a little project I decided to do with matrices is a Sudoku solver. (This is not for credit, this was given as sort of a practice with matrices before a test).
I've gotten mostly through the program so far I'm just stuck on a couple final functions.
I want to write a function called check-block that will take a north-west-corner row a north-west-corner column and a value and check and see if that value can go in that block. So basically the top left of one of the Sudoku 3X3 boxes and itll need to check if the number has all ready occurred or not. I have a check-row and check-col function below that checks each specific row and column to see if a number can go there, but it starts at the very first column or square each time, not sure how to go about making it start from a given northwest corner.
It'd start of something like:
(define (check-block nwr nwc val))
I'm assuming I'll have to use some sort of loop to check each part of the block.
After this I want to write something called valid? which takes a row index r, a column index c, and a value val and checks that it is possible to put the value in the given position.
Those two I really am stuck on, then to end it I know how to think of it as an algorithm stand point. Which is I need four more functions solve, try-row, try-cell, and try-value.
The idea is that solve simply calls try-row 0 which starts filling the puzzle from row 0. The procedure try-row assumes that all the previous rows are properly filled and, if the puzzle is not finished, attempts to make progress by calling (try-cell r 0). The procedure try-cell assumes all the previous rows and the columns to the left are properly filled. If the current row is filled, it proceeds to the next row. If the current cell is not blank, it skips it. Otherwise, if the current cell is blank, it calls (try-value r c 1) which attempts to fill the current cell with 1. The procedure try-value takes the coordinates of a cell and a value v to be placed in the given position. If the value exceeds 9 then the procedure, having failed, returns. If it is possible to put the given value, the procedure tries the next value. If it is possible to put the given value, the board is modified, and the computation proceeds by trying to fill the next cell. If the attempt to fill the next fails, the added value is removed, and the next value is tried.
So here is the code I have so far:
;This function defines an empty cell as _
(define empty #\_)
;This makes it so there are 9 rows in the matrix
(define rows 9)
;This makes it so there are 9 columns in the matrix
(define cols 9)
;This makes it soa block size is considered 3X3
(define block-size 3)
;This makes board be the matri
(define board (make-matrix rows cols empty))
;This function physically builds the matrix
(define read-puzzle
(lambda (fname)
(with-input-from-file
fname
(lambda ()
(let row-loop ([r 0])
(unless (= r rows)
(let col-loop ([c 0])
(if (= c cols)
(row-loop (add1 r))
(begin
(matrix-set! board r c (read-cell))
(col-loop (add1 c)))))))))))
;This reads what cell has what value
(define read-cell
(lambda () (let ([c (read)]) (if (eq? c '-) empty c))))
;This function checks a specific cell to see if it is blank or has a value
(define (blank? r c)
(equal? empty (matrix-ref board r c)))
;This clears the board to an empty 9x9 matrix
(define (clear-board)
(set! board (make-matrix rows cols empty)))
;This function checks if the value given can be put in that row by checking
;if that value all ready occurs in that row giving #t if it doesnt occur and
;#f if it does occur
(define (check-row r val)
(define (cr-helper r c val)
(cond
[(>= c cols) #t]
[(equal? val (matrix-ref board r c)) #f]
[else (cr-helper r (add1 c) val)]))
(cr-helper r 0 val))
;This function checks if the value given can be put in that column by checking
;if that value all ready occurs in that column giving #t if it doesnt occur and
;#f if it does occur
(define (check-col c val)
(define (cc-helper r c val)
(cond
[(>= r rows) #t]
[(equal? val (matrix-ref board r c)) #f]
[else (cc-helper (add1 r) c val)]))
(cc-helper 0 c val))

Your check-block function will need two nested loops, one loop that advances by rows and one loop that advances by columns, starting from the northwest corner. Each of the two loops checks the cell at an offset of 0, 1 or 2 from the northwest corner, and returns #f if it is the same as the target number.
I wrote a somewhat different Sudoku solver based on lists rather than matrices. I'll repeat the code below; you can see the explanation at my blog.
(define (sudoku puzzle)
(define (safe? filled digit cell)
(cond ((null? filled) #t)
((and (= (vector-ref (car filled) 0) (vector-ref cell 0))
(char=? (vector-ref (car filled) 3) digit)) #f)
((and (= (vector-ref (car filled) 1) (vector-ref cell 1))
(char=? (vector-ref (car filled) 3) digit)) #f)
((and (= (vector-ref (car filled) 2) (vector-ref cell 2))
(char=? (vector-ref (car filled) 3) digit)) #f)
(else (safe? (cdr filled) digit cell))))
(define (next digit) (integer->char (+ (char->integer digit) 1)))
(define (new old digit) (vector (vector-ref old 0) (vector-ref old 1) (vector-ref old 2) digit))
(let scan ((s 0) (empty '()) (filled '()))
(if (< s 81)
(let* ((row (quotient s 9))
(col (modulo s 9))
(box (+ (* (quotient row 3) 3) (quotient col 3)))
(digit (string-ref puzzle s))
(cell (vector row col box digit)))
(if (char=? digit #\0)
(scan (+ s 1) (cons cell empty) filled)
(scan (+ s 1) empty (cons cell filled))))
(let solve ((empty empty) (filled filled))
(if (pair? empty)
(let try ((cell (car empty)) (digit (next (vector-ref (car empty) 3))))
(cond ((char<? #\9 digit) ; backtrack
(solve (cons (car filled) (cons (new cell #\0) (cdr empty))) (cdr filled)))
((safe? filled digit cell) ; advance
(solve (cdr empty) (cons (new cell digit) filled)))
(else (try cell (next digit))))) ; try next digit
(let ((str (make-string 81 #\0)))
(do ((filled filled (cdr filled))) ((null? filled) str)
(let* ((cell (car filled)) (s (+ (* (vector-ref cell 0) 9) (vector-ref cell 1))))
(string-set! str s (vector-ref cell 3))))))))))
A Sudoku puzzle is represented as an 81-character string, in row-major order, with empty cells represented as zero. Here is a sample solution:
> (sudoku "700100000020000015000006390200018000040090070000750003078500000560000040000001002")
"789135624623947815451286397237418569845693271916752483178524936562379148394861752"
You can run the program at http://programmingpraxis.codepad.org/PB1czuyF.
You might also enjoy the matrix library in my Standard Prelude.

Related

Quicksort in Scheme using a partition

I have a partition for a quicksort:
(define (partition pivot lst)
((lambda (s) (s s lst list))
(lambda (s l* c)
(if (null? l*)
(c '() '())
(let ((x (car l*)))
(s s (cdr l*)
(lambda (a b)
(if (< x pivot)
(c (cons x a) b)
(c a (cons x b))))))))))
partition code source
Testing:
=>(partition '5 '(1 3 5 7 9 8 6 4 2))
;Value: ((1 3 4 2) (5 7 9 8 6))
How can I implement this partition in a quicksort? I've tried this so far:
(define (quicksort lst)
(if (null? lst) '()
(let* ((y (car lst))
(pn (partition y (cdr lst))))
(append (quicksort (car pn))
(list y)
(quicksort (cdr pn))))))
First, your code is trivially fixed by changing one cdr to cadr:
(define (partition pivot lst)
((lambda (s) (s s lst list))
......)) ; ^^^^ `list` the top continuation
(define (quicksort lst)
(if (null? lst) '()
(let* ((y (car lst))
(pn (partition y (cdr lst))))
(append
(quicksort (car pn))
(list y)
(quicksort (cadr pn))))))
;; ^^^^ cdr --> cadr
because the top continuation used in partition is list, and so the call
(partition pivot lst)
is equivalent to the call
(list { x IN lst SUCH THAT x < pivot }
{ x IN lst SUCH THAT x >= pivot } )
(the parts in {...} are pseudocode, where we don't care about the implementation, just the results)
And so to access the two parts of that list built by partition you need to use car and cadr.
Or you could keep the cdr in the accessing part of your code in quicksort if you'd change that top continuation to cons:
(define (partition pivot lst)
((lambda (s) (s s lst cons))
......)) ; ^^^^ `cons` the top continuation
(define (quicksort lst)
(if (null? lst)
'()
(let* ((y (car lst))
(pn (partition y (cdr lst))))
(append
(quicksort (car pn))
(list y)
(quicksort (cdr pn))))))
;; ^^^^ `cdr` works fine with `cons`
This because of the general principle in programming, where the functions used to build our data dictate which functions are to be used to access that data:
(list <A> <B> )
car cadr
(cons <A> <B> )
car cdr
( this particular correspondence is because (list <A> <B>) is the same as (cons <A> (cons <B> '())) and (cadr <C>) is the same as (car (cdr <C>)): )
(list <A> <B> )
=
(cons <A> (cons <B> '()))
car cdr
car
And conversely, the functions we use to access our data dictate the implementation of the function which must be used to build that data.
Of course that way of coding in your question is considered unnecessarily convoluted by modern standards since it emulates recursion through argument passing and reuse, -- just like in the famous Y combinator, -- but any Scheme worthy of its name already supports recursion.
So this partition would normally be written as the fully equivalent yet more readable code using the "named let" construct,
(define (partition pivot lst)
(let s ( (l* lst) ; first `l*` is `lst`
(c cons) ) ; top `c` is `cons`
(if (null? l*)
(c '() '())
(let ((x (car l*)))
(s (cdr l*)
(lambda (a b)
(if (< x pivot)
(c (cons x a) b)
(c a (cons x b)))))))))
except the name loop is conventionally used in place of s here (which itself most probably is intended as the shortening of "self").
But the true trouble with your quicksort/partition pair is algorithmic.
Yes I say pair (in non-cons sense of course) since the two go together -- just as with the data access/creation functions which must work together too.
Implementation of one dictates the implementation of the other -- in both directions, too. partition's code dictates quicksort's, or if we'd written quicksort first, we'd need to implement the partition in the corresponding way -- so that the two work together. Which means quicksort indeed producing the correct results, turning any input list into a sorted one:
(quicksort lst) --->
{ xs SUCH THAT
FOR ANY splitting xs = { ..., x, ...ys }
AND ANY splitting ys = { ..., y, ... }
IT HOLDS THAT x <= y
AND ALSO xs is a permutation of lst
(which implies (length lst) == (length xs))
}
So then, what is that trouble? It is that the true quicksort does no work whatsoever after the partitioning. None:
(define (quicksort! lst)
(if (null? lst)
'()
(let* ((y (car lst))
(pn (partition! y lst)))
(quicksort! (car pn)) ; no `append`, NB!
(quicksort! (cdr pn))))) ; no (list y) either
How is that even possible? What kind of partition! implementation would make that work? Well, most certainly not a functional one.
Instead it must be changing (i.e. mutating) the very lst itself somehow:
{ a, b, c, ....., k, l, m, ..... }
-->
{ d, e, ...., p, n, o, ..... }
~~~~~~~~~~~ ~~~~~~~~~~~
where we denote with p the partition point -- so that indeed all that's left to do after this kind of partitioning "in-place" is to sort the first part, and then to sort the second part, -- and then there's nothing more left to be done, after that! Which was the key insight in the original Tony Hoare's formulation of it:
TO SORT
{ a, b, c, ....., k, l, m, ..... } DO:
PARTITION it into
{ d, e, ...., p, n, o, ..... } AND THEN:
~~~~~~~~~~~ ~~~~~~~~~~~
SORT! SORT!
DONE.
This partitioning is usually implemented with swap! which actually swaps two elements in the underlying data structure. Most usually that data structure is an array with its facilities to change the value stored in it at any given index.
But it can also be a list, where the change i.e. mutation can be done with the set-car! primitive.
Looks like we'd need to build a list of cdrs out of the input list, and another one in reverse, -- to be able to iterate over them in both directions, back and forth, -- to make that happen.
I'll leave that for another day, for now.
Once you have the partition, there is still a small step to do.
Take care, you need to be sure partition splits the input in smaller sets all the time. In other word, partition not to return some empty set. The pivot can go in any of the sets and use this fact to check that you do not return an empty set, in case your comparison operator does not really decrease the size of the input. This is why I inserted the equality operator -- to be able to check if I insert the pivot in the first returned set or in the second one.
(define (partition pivot lst ret)
((lambda (s)
(s s lst
(lambda (a b p*)
(if (and (null? a) (null? b))
(ret (list pivot) (cdr p*))
(if (null? a)
(ret p* b)
(if (null? b)
(ret a p*)
(if (< (car b) pivot)
(ret a (append p* b))
(if (< (car a) pivot)
(ret (append a p*) b)
(error "never here")))))))))
(lambda (s l* c)
(if (null? l*)
(c '() '() '())
(let ((x (car l*)))
(s s (cdr l*)
(lambda (a b p*)
(if (= x pivot)
(c a b (cons pivot p*))
(if (< x pivot)
(c (cons x a) b p*)
(c a (cons x b) p*))))))))))
(define choose-pivot car)
In a real implementation, you will all the time use vectors and this is why the append will not be present, as, sorting on the place, at the end of partition, both sides will be sorted relatively one to the other. Here, we need to reassemble the 2 sides using append:
(define (quicksort lst)
(if (null? lst) '()
(if (null? (cdr lst))
lst
(let* ((pivot (choose-pivot lst)))
(partition pivot lst
(lambda (p< p>)
(append
(quicksort p<)
(quicksort p>))))))))
A test:
1 ]=> (quicksort '(1 3 5 7 9 8 6 4 2))
;Value: (1 2 3 4 5 6 7 8 9)
1 ]=> (quicksort '(1 9 3 8 5 7 7 6 9 5 8 4 6 3 4 2 2 1))
;Value: (1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9)
I used as pivot the first element of the input to split, but you can redefine the choose-pivot to select other element.
In practice, this algorithm is used in combination with other sorts -- when the input has fewer than 4-8 elements, the quicksort is not recurred any more, but other sorting is used for the lowest cases of recurrence relation.
I used directly < in the code -- you can insert it as a parameter in case you prefer a more generic procedure... In any case, the operator that you use needs to simulate the equality and different of in the same time.
UPDATE I have updated the partition, such that to consider duplicated elements. In my first version, it ignored duplicated elements.

Solving Eight-queens in scheme

I'm starting to write a function to see if a queen is 'safe' from the other positions on the board, the board is in the form of (row col) and 1-indexed. Here is what I have thus far:
(define (get-row p) (car p))
(define (get-col p) (cadr p))
(define (is-equal p1 p2)
(and (= (car p1) (car p2)) (= (cadr p1) (cadr p2))))
(define (safe? k positions)
(filter
(lambda (p) (not (and (is-equal p
(list (get-row p) k))
(is-equal p
(list (+ (get-row p) (- k (get-col p)))
k
))
(is-equal p
(list (- (get-row p) (- k (get-col p)))
k
)))))
positions))
I am trying to call it something like:
(safe? 4 '((3 1) (1 2) (4 3) (2 4)))
To see if the fourth queen (in the forth column) on the board with position (2 4) is safe.
However, what I have currently is wide of the mark and returns basically all the 'other' columns instead of the one I want. What would be a better way to do this?
There are many ways to solve this problem. For starters, I'd suggest a simpler representation for the board, I chose to use a list of numbers. The indexes in the list start from one and indicate the queen's column and the value its row (origin of coordinates is on the upper-left corner, new positions are adjoined at the end of the list); all the other positions are assumed to be empty. For instance, the following board:
(. Q)
(Q .)
Would be represented by the list '(2 1). With my representation, the safe? procedure looks like this - and notice that the diagonals? check is a bit trickier to implement:
; a new queen is safe iff there are no other queens in the same
; row nor in any of the diagonals preceding its current position
; we don't need to check the column, this is the only queen on it
(define (safe? col board)
(let ((row (list-ref board (- col 1))))
(and (<= (number-occurrences row board) 1)
(diagonals? row board))))
; counts how many times an element appears on a list
(define (number-occurrences e lst)
(count (curry equal? e) lst))
; traverses the board looking for other queens
; located in one of the diagonals, going backwards
; starting from the location of the newest queen
(define (diagonals? row board)
(let loop ((lst (cdr (reverse board)))
(upper (sub1 row))
(lower (add1 row)))
(or (null? lst)
(and (not (= (car lst) upper))
(not (= (car lst) lower))
(loop (cdr lst) (sub1 upper) (add1 lower))))))
The result is as expected:
(safe? 4 '(2 4 1 3))
=> #t
You can adapt the above code to use a different origin of coordinates if you wish so, or to use pairs of coordinates to represent the queens.

Minimax algorithm not working as expected

I am building an AI for a game of tick-tack-toe, using the stub given in the Realm of Racket book as a basis. So far, everything has gone well. However, when I try to run my minimax function on the root of the tree, it returns a list of the lowest possible values you can get by running it (With either player as the predicate).
Here is a code dump of the function:
(define (minimax tree player depth)
(define (generate-score tree player depth)
(define won (winner (ttt-tree-board tree)))
(if (<= depth 0) 0
(+ (cond
[(equal? won player) 1]
[(false? won) 0]
[else -1])
(apply +
(for/list ([t (ttt-tree-moves tree)])
(generate-score (second t) player (sub1 depth)))))))
(for/list ([t (ttt-tree-moves tree)])
(generate-score (second t) player depth)))
This is only my minimax function, because none of the others (except for winner) need to be displayed. Here is winner:
(define (winner board)
(or
(ormap (lambda (row) (if (all-equal? row) (first row) #f)) board) ; Horizontal
(ormap (lambda (i) (if ; Vertical
(all-equal? (map (lambda (j) (list-ref (list-ref board j) i)) (stream->list (in-range (length board)))))
(list-ref (first board) i) #f))
(stream->list (in-range (length board))))
(if ; Diagonal
(all-equal? (map (lambda (i) (list-ref (list-ref board i) i)) (stream->list (in-range (length board)))))
(first (first board)) #f)
(if ; Diagonal cont.
(all-equal? (map (lambda (i) (list-ref (reverse (list-ref board i)) i)) (stream->list (in-range (length board)))))
(last (first board)) #f)))
(It is a bit sloppy, so if anyone has an idea to make it shorter, tell me your suggestion)
ttt-tree structures follow this pattern:
(ttt-tree board moves)
In which board is a 2D array corresponding to the tick-tack-toe board (with the form '((X - O) (O X -) (- X O))), and moves is a list of possible moves that can be made from that node, each of which is a list with two elements: the position that changed, and a ttt-tree which forms the next node. So (second t) refers to the next node, if t is (list-ref (ttt-tree-moves #<ttt-tree>) x)
My original thought was that there may be some error in the cond, but I'm using equal? not eq?, so I don't see how that would be a problem. The other possibility is that I'm defining winner wrong, but I have tested it many times so I don't know what could go wrong. Please help!
It turns out that the problem was that in my winner function, I never checked if the winner was "-", the empty tile. Therefore that would trigger in most cases, activating the else clause and resulting in a score of -1.

Compare a list of numbers with a variable

The function below is intended to compare every number in a list (2nd parameter) with the first parameter and for every num in the list that is greater than the second param, count it and return the total amount of elements in the list that were greater than the 'threshold'
The code I have doesn't run because I have tried to learn how recursion in Dr. Racket works, but I can't seem to understand. I am just frustrated so just know the code below isn't supposed to be close to working; functional programming isn't my thing, haha.
(define (comp-list threshold list-nums)
(cond [(empty? list-nums) 0]
[(cons? list-nums) (let {[my-var 0]}
(map (if (> threshold (first list-nums))
threshold 2) list-nums ))]))
The following doesn't use lambda of foldl (and is recursive) - can you understand how it works?
(define (comp-list threshold list-nums)
(cond [(empty? list-nums) 0]
[else
(cond [(> (car list-nums) threshold) (+ 1 (comp-list threshold (cdr list-nums)))]
[else (comp-list threshold (cdr list-nums))])]))
Tested:
> (comp-list 1 '(1 1 2 2 3 3))
4
> (comp-list 2 '(1 1 2 2 3 3))
2
> (comp-list 3 '(1 1 2 2 3 3))
0
map takes a procedure as first argument and applied that to every element in the given list(s). Since you are counting something making a list would be wrong.
foldl takes a procedure as first argument, the starting value as second and one or more lists. It applies the procedure with the elements and the starting value (or the intermediate value) and the procedure get to decide the next intermediate value. eg. you can use it to count a list:
(define (my-length lst)
(foldl (lambda (x acc) (+ acc 1))
0
lst))
(my-length '(a b c)) ; ==> 3
You can easily change this to only count when x is greater than some threshold, just evaluate to acc to keep it unchanged when you are not increasing the value.
UPDATE
A recursive solution of my-length:
(define (my-length lst)
;; auxiliary procedure since we need
;; an extra argument for counting
(define (aux lst count)
(if (null? lst)
count
(aux (cdr lst)
(+ count 1))))
;; call auxiliary procedure
(aux lst 0))
The same alteration to the procedure to foldl have to be done with this to only count in some circumstances.
(define (comp-list threshold list-nums)
(cond
[(empty? list-nums) ; there are 0 elements over the threshold in an empty list
0]
[(cons? list-nums) ; in a constructed list, we look at the the first number
(cond
[(< threshold (first list-nums))
(+ 1 ; the first number is over
(comp-list threshold (rest list-nums))] ; add the rest
[else
(comp-list threshold (rest list-nums))])])) ; the first number is lower
A simple functional start
#lang racket
(define (comp-list threshold list-nums)
(define (my-filter-function num)
(< num threshold))
(length (filter my-filter-function list-nums)))
Replacing define with lambda
#lang racket
(define (comp-list threshold list-nums)
(length (filter (lambda (num) (< num threshold))
list-nums)))
Racket's implementation of filter
In DrRacket highlighting the name of a procedure and right clicking and selecting "jump to definition in other file" will allow review of the source code. The source code for filter is instructive:
(define (filter f list)
(unless (and (procedure? f)
(procedure-arity-includes? f 1))
(raise-argument-error 'filter "(any/c . -> . any/c)" f))
(unless (list? list)
(raise-argument-error 'filter "list?" list))
;; accumulating the result and reversing it is currently slightly
;; faster than a plain loop
(let loop ([l list] [result null])
(if (null? l)
(reverse result)
(loop (cdr l) (if (f (car l)) (cons (car l) result) result)))))

Scheme - Replacing elements in a list with its index

I am trying to replace the elements in a scheme list with its position.
For example, calling:
(position '((a b) c))
should return:
'((0 1) 2)
So far, my code keeps the list format, but the index is not updating.
(define (position term1)
(define index 0)
(cond [(null? term1) '()]
[(list? term1) (cons (position (car term1)) (position(cdr term1)))]
[else (+ 1 index) index]))
When (position '((a b) c)) is called, it returns
'((0 0) 0)
Can anybody explain why the index isn't updating?
There are a couple things wrong: first notice that every time you recursively call position, index is bound to zero.
Second, look at your else branch. (+ 1 index) evaluates to 1 (it does not change any variables) and index evaluates to 0. This branch can only evaluate to one thing, so what happens is the last one is returned and the rest are discarded. This is where your zeroes come from.
It seems like within your function you are trying to keep a global state (the current index) and modify it each time you label a leaf. The "modifying state" part is not good functional style, but if you are okay with that then take a look at set!.
Here is one solution using CPS:
#lang racket
(define (index xs [i 0] [continue (λ (xs i) xs)])
(match xs
[(cons x xs) (index x i
(λ (js j)
(index xs j
(λ (ks k)
(continue (cons js ks) k)))))]
['() (continue '() i)]
[x (continue i (+ i 1))]))
; Example
;(index '((a b) (c d) x (e (f g) h)))
; '((0 1) (2 3) 4 (5 (6 7) 8))
Here (index xs i continue) replaces the elements in xs with their indices, the count starts from i. Let's say the result of indexing xs is js, then continue is called with the indexing result and the next index to be used: (continue js j).
Daenerys Naharis already pointed out what's wrong, so let me point out some features of Scheme and Racket you may be unaware of that you could use in a solution that maintains functional style.
This is called a named let:
(let loop ((index 0)
(result '()))
(if (= index 10)
(reverse result)
(loop (+ 1 index) (cons index result)))
Within the let form, loop is bound as a function that takes all the local variables as arguments. Calling it recursively calls the let form itself. This way you can make index an argument without making it an argument of position. You can also put the result in an argument, which allows you to make the call to loop a tail call.
The other feature is less widespread among existing Scheme implementations: Optional arguments. In Racket, they're defined like this:
(define (position term1 (index 0)) ...)
Then position can be called with or without the index argument.
An example using mutation that maintains it's own state so that each item of each list has a unique id.
Example Usage:
> (position '((a b) c))
'((0 1) 2)
> (position '((a b) c (d (e))))
'((3 4) 5 (6 (7)))
Example Implementation:
#lang racket
(provide position)
(define base -1)
(define (indexer)
(set! base (add1 base))
base)
(define (position list-of-x)
(cond [(null? list-of-x) null]
[else
(define head (first list-of-x))
(cond [(list? head)
(cons (position head)
(position (rest list-of-x)))]
[else (cons (indexer)
(position (rest list-of-x)))])]))

Resources