SICP Exercise 2.5 - How to represent negative numbers? - scheme

I'm currently reading the SICP, and working on Exercise 2.5 :
Exercise 2.5. Show that we can represent pairs of nonnegative integers using only numbers and arithmetic operations if we represent the pair a and b as the integer that is the product 2a3b. Give the corresponding definitions of the procedures cons, car, and cdr.
And I've found a code:
(define (my-cons a b)
(* (expt 2 a) (expt 3 b)))
(define (my-car x)
(define (car-iter x count)
(if (= 0 (remainder x 2))
(car-iter (/ x 2) (+ 1 count))
count))
(car-iter x 0))
(define (my-cdr x)
(define (cdr-iter x count)
(if (= 0 (remainder x 3))
(cdr-iter (/ x 3) (+ 1 count))
count))
(cdr-iter x 0))
My question is : What if the requirement of "Nonnegative integers" needs to be changed to "Accept both negative and nonnegative integers" ?
Example :
> (define x (my-cons 2 -5))
> (my-car x)
2
> (my-cdr x)
-5
How to modify the code? I can't figure it out.
Thank you. May you have a great day.

As amalloy said in a comment this is really a maths problem. This encoding works because of the fundamental theorem of arithmetic, which is that any positive natural number has a unique prime factorisation: every positive natural can be represented uniquely as the product of a number of primes raised to powers, where in particular 1 is the product of no primes.
So you could encode the sign of the integers using one or more additional prime factors (you only need one, in fact, as you can for instance write the thing as 2^a3^b5^s where s is an integer in [0,3] which encodes the signs of both elements).
An alternative way is simply to use the existing representation but to map the integers to the naturals. This is nice because it's a practical demonstration that there are no more integers than naturals. Such a map might be:
if i >= 0 then 2i.
otherswise -2i - 1.
It's easy to see that this is a one-to-one correspondence, and also that 0 maps to 0 (which makes 0 a nice value for nil).
Here are these maps, written (sorry) in typed Racket as I'm trying to work out if I can use it.
(define (Z->N (i : Integer)) : Natural
;; map an integer to a natural
(if (>= i 0)
(* i 2)
(- (* (- i) 2) 1)))
(define (N->Z (n : Natural)) : Integer
;; map the naturals into the integers
(let-values ([(q r) (quotient/remainder n 2)])
(if (zero? r)
q
(- (- q) 1))))
Now there is another problem with the implementation you have: it will happily handle numbers which are not of the form 2^a3^b, for instance anything which has other prime factors. The way to deal with that is to check that numbers are of that form when extracting the powers: in practice this means checking the number is of the form 2^a*3^b*1.
So the code below does this, as well as encoding integers as above. This again is in typed Racket (sorry, again), and it also makes use of multiple values and probably some other things which only exist in Racket.
(define (defactor (n : Natural) (p : Natural)) : (Values Natural Natural)
;; Given n and a factor p, return m where p does not divide m,
;; and j, the number of factors of p removed (so n = m*p^j)
(let df-loop ([m : Natural n]
[j : Natural 0])
(let-values ([(q r) (quotient/remainder m p)])
(if (zero? r)
(df-loop q (+ j 1))
(values m j)))))
(define (kar&kdr (k : Positive-Integer)) : (Values Integer Integer)
;; Given something which should be a kons, return its kar & kdr.
;; If it is not a kons signal an error
(let*-values ([(k2 encoded-kar) (defactor k 2)]
[(k23 encoded-kdr) (defactor k2 3)])
(unless (= k23 1)
(error 'kar&kdr "not a cons"))
(values (N->Z encoded-kar) (N->Z encoded-kdr))))
(define (kons (the-kar : Integer) (the-kdr : Integer)) : Positive-Integer
(* (expt 2 (Z->N the-kar))
(expt 3 (Z->N the-kdr))))
(define (kar (the-kons : Positive-Integer)) : Integer
(let-values ([(the-kar the-kdr) (kar&kdr the-kons)])
the-kar))
(define (kdr (the-kons : Positive-Integer)) : Integer
(let-values ([(the-kar the-kdr) (kar&kdr the-kons)])
the-kdr))
We can go a little further and define a representation of the empty list, which will be 0 and a way of making lists:
;;; since 2^a3^b is never zero, 0 is a good candidate for the empty
;;; list: 'kill' is a pun on 'nil'.
;;;
(define kill : Zero 0)
;;; And now we can write some predicates and a version of list.
;;; (kist 1 2 3) takes a very, very long time.
;;;
(define (kill? (x : Natural)) : Boolean
(zero? x))
(define (kons? (x : Natural)) : Boolean
(not (kill? x)))
(define (kist . (l : Integer *)) : Natural
(let kist/spread ((lt l))
(if (null? lt)
kill
(kons (first lt) (kist/spread (rest lt))))))
And now
> (define d (kons 123 -456))
> d
- : Integer [more precisely: Nonnegative-Integer]
51385665200410193914365219310409629004573395973849642473134969706165383608831740620563388986738635202925909198851954060195023302783671526117732269828652603388431987979605951272414330987611274752111186624164906143978901704325355283206259678088536996807776750955110998323447711166379786727609752016045005681785186498933895920793982869940159108073471074955985333560653268614500306816876936016985137986665262182684386364851688838680773491949813254691225004097103180392486216812280763694296818736638062547181764608
> (kar d)
- : Integer
123
> (kdr d)
- : Integer
-456
> (kdr (+ d 1))
kar&kdr: not a cons [,bt for context]
If you try to compute, say (kist 1 2 3) it will take a very, very long time.

Related

How do I write a division function in scheme

This is my first week using scheme, and I'm stuck on a simple problem. I want to write a function that does simple integer division. This is what I've written and I'm getting a bad syntax error. Any help on how to fix this and make the code work?
(define divisible-by
(lambda (a b)
(if (= a b)
(display #f))
)
(if (= (remainder a b) 0)
(display #t)
(else
(display #f))
)
)
Here is an answer that you won't be able to submit but which shows you how you might approach this.
I assume you are not allowed to simply use division, so one way to divide n by d, assuming n is a natural number and d is a non-zero natural number, is to repeatedly subtract d from n while incrementing a result, r, until you get a number which is less than d, which is the remainder. Here is that:
(define (div/rem n d)
;; Return the quotient and remainder of n by d
;;
;; You should perhas check they are naturals here, and that d is non-zero
;;
(define (div/rem-loop m r)
(if (< m d)
(values r m)
(div/rem-loop (- m d) (+ r 1))))
(div/rem-loop n 0))
There are more concise ways of writing this (named let is the obvious one).

How to check if a relation represented as a matrix (list of lists) is antisymmetric?

How can I check if a relation represented as a matrix (list of lists) is antisymmetric?
For example, the function should return true for;
(antisymm ((1 1 0) (0 0 1) (0 0 0)))
Example:
(antisymm ((1 1 0) (0 0 1) (0 0 0))) returns #t
(antisymm ((1 1 0) (0 0 1) (0 1 0))) returns #f
If you are going to be dealing with matrices (or any data type) the first thing to do is to write some abstractions. Matrices are not lists of lists: they might be represented as lists of lists, but they're matrices.
So let's assume some abstractions which I will not write:
matrix-rows tells you how many rows a matrix has;
matrix-cols tells you how many columns a matrix has;
matrix-ref retrieves an element of a matrix.
I will also assume zero-based indexing (which is not what mathematicians assume).
You might also want a make-matrix function.
Then it is relatively easy to write a symmetry checker:
(define (symmetry-test? m symmetry-predicate?)
;; Zero-based indexing assumed
(define max-row (- (matrix-rows m) 1))
(define max-col (- (matrix-cols m) 1))
(cond
((not (= max-row max-col))
(error "not square"))
((= max-row 0)
;; 1x1 is symmetric by definition
#t)
(else
(let check ((row 1)
(col 0))
;; Note we need to check diagonal elts for skew case
(cond
((> col max-col)
#t)
((> col row)
(check (+ row 1) 0))
((symmetry-predicate? (matrix-ref m row col)
(matrix-ref m col row))
(check row (+ col 1)))
(else
#f))))))
And now
(define (matrix-symmetric? m)
;; a matrix is symmetric if a[r,c] = a[c,r] for all r, c
(symmetry-test? m =))
(define (matrix-skew? m)
;; a matrix is skew is a[r,c] = - a[c,r] for all r, c
(symmetry-test? m (λ (a b) (= a (- b)))))
For additional bonus points: why does this show that a list of lists is an absolutely terrible representation for a matrix?

Why am I getting an error with this simple scheme code?

(define ZERO (lambda (f x) x))
(define ONE (lambda (f x) (f x)))
(define SUCC (lambda (n) (lambda (f x) (f (n f x)))))
(display (ZERO 1 0))
(display (ONE 1 0))
(display ((SUCC ZERO) 1 0))
The ZERO function works fine. When I run this code, I get an error,
ERROR: invalid application: (1 0)
for ONE, SUCC function.
How can I fix my code to make it work?
This is the Church encoding of numbers; the number K is represented by K applications of a function f to some argument x.
(The identities of the function and that argument are, surprisingly enough, irrelevant - you can build all of mathematics without caring.)
You can make it make a bit of sense with suitable choices of f and x - try, for instance, 0 and
(define (inc x) (+ x 1))
so the number K is represented by adding 1, K times, to 0.
> (ZERO inc 0)
0
> (ONE inc 0)
1
> ((SUCC ONE) inc 0)
2
You can also add some convenience with an evaluation function:
> (define (number n) (n inc 0))
> (number ZERO)
0
> (number ONE)
1
> (number (SUCC (SUCC (SUCC (SUCC ONE)))))
5

Scheme Procedure that takes an argument and outputs a value

I am trying to write a procedure called bal-val that has to take in a single argument and output the value of the ball. The values for the balls are R = 5, G=4, B = 3, and W = 1.
The code I have is:
(define (bal-val n)
(if (= n R))
(= n 5)
(if (= n G))
(= n 4)
(if (= n B))
(= n 3)
(if (= n W))
(= n 1))
First of all (= n 5) applys the function = to the constant 5 and the variable n. Therefore it returns a Boolean value, it does not set n to be 5.
The main issue though is wrong use of Predicates:
= predicate is used to check whether two numbers are equal. If you supply anything else (but a number) it will raise an error.
The eq? predicate is used to check whether its two parameters respresent the same object in memory.
The equal? predicate tests for same value in primitive types and can also check two lists, vectors, etc.
This is what you are trying to do:
(define (bal-val n)
(if (equal? n 'R)
5
(if (equal? n 'G)
4
(if (equal? n 'B)
3
(if (equal? n 'W)
1
(error 'not_found))))))
You might want to use cond in this case as it resembles switch behavior more naturally. Done like so:
(define (bal-val-cond n)
(cond ((equal? n 'R) 5)
((equal? n 'G) 4)
((equal? n 'B) 3)
((equal? n 'W) 1)
(else (error 'not_found))))
coding 101 - ALWAYS indent your code correctly, it makes it understandable and with time errors will stand out and you will be able to spot them much quicker.

Reversing an integer

I am trying to write a function which takes an input number and outputs the number in reverse order.
Ie:
Input -> 25
Output -> 52
Input -> 125
Output -> 521
I am new to lisp, if its helpful here is the working function in c++
function.cpp
int revs(int rev, int n)
{
if (n <= 0)
return rev;
return revs((rev * 10) + (n % 10), n/10);
}
I have written it in Racket as follows:
(define (revs rev n)
(if (<= n 0)
rev
(revs (+ (* rev 10) (modulo n 10)) (/ n 10))))
But when I run it with (revs 0 125) I get this error:
modulo: contract violation
expected: integer?
given: 25/2
argument position: 1st
other arguments...:
10
Certainly I am doing something incorrect here, but I am unsure of what I am missing.
The division operator / doesn't do integer division, but general division, so when you call, e.g., (/ 25 2), you don't get 12 or 13, but rather the rational 25/2. I think you'd want quotient instead, about which the documentation has:
procedure (quotient n m) → integer?
n : integer?
m : integer?
Returns (truncate (/ n m)). Examples:
> (quotient 10 3)
3
> (quotient -10.0 3)
-3.0
> (quotient +inf.0 3)
quotient: contract violation
expected: integer?
given: +inf.0
argument position: 1st
other arguments...:
3
Treating the operation lexicographically:
#lang racket
(define (lexicographic-reverse x)
(string->number
(list->string
(reverse
(string->list
(number->string x))))))
Works[1] for any of Racket's numerical types.
[edit 1] "Works," I realized, is context dependent and with a bit of testing shows the implicit assumptions of the operation. My naive lexicographic approach makes a mess of negative integers, e.g. (lexicographic-reverse -47) will produce an error.
However, getting an error rather than -74 might be better when if I am reversing numbers for lexicographic reasons rather than numerical ones because it illuminates the fact that the definition of "reversing a number" is arbitrary. The reverse of 47 could just as well be -74 as 74 because reversing is not a mathematical concept - even though it might remind me of XOR permutation.
How the sign is handled is by a particular reversing function is arbitrary.
#lang racket
;; Reversing a number retains the sign
(define (arbitrary1 x)
(define (f n)
(string->number
(list->string
(reverse
(string->list
(number->string n))))))
(if (>= x 0)
(f x)
(- (f (abs x)))))
;; Reversing a number reverses the sign
(define (arbitrary2 x)
(define (f n)
(string->number
(list->string
(reverse
(string->list
(number->string n))))))
(if (>= x 0)
(- (f x))
(f (abs x))))
The same considerations extend to Racket's other numerical type notations; decisions about reversing exact, inexact, complex, are likewise arbitrary - e.g. what is the reverse of IEEE +inf.0 or +nan.0?
Here is my solution for this problem
(define (reverseInt number)
(define (loop number reversedNumber)
(if (= number 0)
reversedNumber
(let ((lastDigit (modulo number 10)))
(loop (/ (- number lastDigit) 10) (+ (* reversedNumber 10) lastDigit)))))
(loop number 0))
Each time we multiply the reversed number by 10 and add the last digit of number.
I hope it makes sense.
A R6RS version (will work with R7RS with a little effort)
#!r6rs
(import (rnrs)
(srfi :8))
(define (numeric-reverse n)
(let loop ((acc 0) (n n))
(if (zero? n)
acc
(receive (q r) (div-and-mod n 10)
(loop (+ (* acc 10) r) q)))))
A Racket implementation:
#!racket
(require srfi/8)
(define (numeric-reverse n)
(let loop ((acc 0) (n n))
(if (zero? n)
acc
(receive (q r) (quotient/remainder n 10)
(loop (+ (* acc 10) r) q)))))
With recursion, you can do something like:
#lang racket
(define (reverse-num n)
(let f ([acc 0]
[n n])
(cond
[(zero? n) acc]
[else (f (+ (* acc 10) (modulo n 10)) (quotient n 10))])))

Resources