Map function with index as one of arguments in LISP - scheme

Is there any built-in function in LISP languages (or Racket in particular) that would work like map, but pass index of the element as one of the arguments to the mapping function?
Example of such function would be:
(define map-index (lambda (func list)
(map func list (build-list (length list) (lambda (i) i)))))
;usage:
> (map-index cons '(a b c d))
;output:
'((a . 0) (b . 1) (c . 2) (d . 3))
Obviously this is not a very efficient implementation and doesn't support multiple lists as arguments, like regular map does.

Racket
You can write a dead-simple version of map-index using the Racket range procedure and mapping over the result:
(define (map-index-1 f xs)
(map f xs (range (length xs))))
In some situations you might want the indices first:
(define (map-index-2 f xs)
(map f (range (length xs)) xs))
If you want to be able to use map-index over multiple lists, you can pass the list arguments to an optional parameter. Here, apply applies the map procedure to a list constructed from the function f, the input lists, and a range list:
(define (map-index-3 f . xs)
(apply map (cons f
(append xs
(list (range (length (car xs))))))))
But it might make more sense to place the indices first when mapping over multiple lists:
(define (map-index-4 f . xs)
(apply map (cons f
(cons (range (length (car xs)))
xs))))
scratch.rkt> (map-index-1 cons '(a b c d))
'((a . 0) (b . 1) (c . 2) (d . 3))
scratch.rkt> (map-index-2 cons '(a b c d))
'((0 . a) (1 . b) (2 . c) (3 . d))
scratch.rkt> (map-index-3 list '(a b c d) '(one two three four) '(w x y z))
'((a one w 0) (b two x 1) (c three y 2) (d four z 3))
scratch.rkt> (map-index-4 list '(a b c d) '(one two three four) '(w x y z))
'((0 a one w) (1 b two x) (2 c three y) (3 d four z))
Scheme
Standard Scheme does not have a built-in range procedure, but it is easy enough to write a simple version. These solutions will work on any R4RS, R5RS, R6RS, or R7RS Scheme implementation. This version of range does more than is required for the current application, taking a step argument which can be positive or negative:
(define (range start stop step)
(if (or (and (> step 0)
(>= start stop))
(and (<= step 0)
(<= start stop)))
'()
(cons start (range (+ start step) stop step))))
Having defined a range procedure, the same approach used for the Racket solutions above can be used in Scheme:
(define (map-index-5 f xs)
(map f xs (range 0 (length xs) 1)))
(define (map-index-6 f xs)
(map f (range 0 (length xs) 1) xs))
(define (map-index-7 f . xs)
(apply map (cons f
(append xs
(list (range 0 (length (car xs)) 1))))))
(define (map-index-8 f . xs)
(apply map (cons f
(cons (range 0 (length (car xs)) 1)
xs))))
> (map-index-5 cons '(a b c d))
((a . 0) (b . 1) (c . 2) (d . 3))
> (map-index-6 cons '(a b c d))
((0 . a) (1 . b) (2 . c) (3 . d))
> (map-index-7 list '(a b c d) '(one two three four) '(w x y z))
((a one w 0) (b two x 1) (c three y 2) (d four z 3))
> (map-index-8 list '(a b c d) '(one two three four) '(w x y z))
((0 a one w) (1 b two x) (2 c three y) (3 d four z))
A map-range Procedure for Standard Scheme
This method can be extended to use numbers in a more complex range that may not represent indices by taking advantage of the capabilities of a range function. Using the range definition from above, this map-range procedure still works on R4RS to R7RS Scheme implementations:
(define (map-range f start step . xs)
(let ((stop (+ start (* step (length (car xs))))))
(apply map (cons f
(cons (range start stop step)
xs)))))
> (map-range cons 2 2 '(a b c d))
((2 . a) (4 . b) (6 . c) (8 . d))
> (map-range list 5 5 '(a b c d) '(one two three four) '(w x y z))
((5 a one w) (10 b two x) (15 c three y) (20 d four z))
> (map-range cons 2 -2 '(a b c d))
((2 . a) (0 . b) (-2 . c) (-4 . d))
> (map-range list 5 -5 '(a b c d) '(one two three four) '(w x y z))
((5 a one w) (0 b two x) (-5 c three y) (-10 d four z))

Not exactly, but there are other things for similar goals, like for/list with in-naturals or in-indexed.
For example instead of (map-index f lst), the pattern would be
(for/list ([x lst] [i (in-naturals)]) (f x i))
or
(for/list ([(x i) (in-indexed lst)]) (f x i))
And either of those patterns could be used to implement map-index as well as your combination of map and build-list.
Racket's iteration forms like for/list are more flexible than a fixed set of map-like functions.
Concrete Examples:
> (for/list ([x '(a b c d)] [i (in-naturals)]) (cons x i))
'((a . 0) (b . 1) (c . 2) (d . 3))
> (for/list ([(x i) (in-indexed '(a b c d))]) (cons x i))
'((a . 0) (b . 1) (c . 2) (d . 3))
Or if you still want a map-index function you could define it more succinctly using this.
> (define (map-index f lst)
(for/list ([(x i) (in-indexed lst)]) (f x i)))
> (map-index cons '(a b c d))
'((a . 0) (b . 1) (c . 2) (d . 3))

Related

Can one use cons to do ((a . b) . (c . d)) and if not any other means or dot pair cannot have 2nd element like this?

;;; <- can one use cons to do ((a . b) . (c . d))?
(define x (cons a b)); nil -- should it be error
(define x (cons 'a 'b)); (a . b)
(define y (cons 'c 'd)); (c . d)
(define z00 (cons x y)) ; (((a . b) c . d) <- cannot use cons to do ((a . b) . (c . d))?
(define z01 (cons x 'y)) ; ((a . b) . y)
(define z10 (cons 'x y)) ; (x c . d)
(define z11 (cons 'x 'y)); (x . y))
(define z (list x y z00 z01 z10 z11))
; ((a . b) (c . d) ((a . b) c . d) ((a . b) . y) (x c . d) (x . y))
;;; and if not any other means or dot pair cannot have 2nd element like this?
Yes, you can. And the language has a wonderful predicate called equal? which will allow you to test this:
> (equal? (cons (cons 'a 'b) (cons 'c 'd))
'((a . b) . (c . d)))
#t
> (equal? '((a . b) . (c . d))
'((a . b) c . d))
#t
And you can even write a little display function which will confirm this:
(define (display-thing thing)
(if (cons? thing)
(begin
(display "(")
(display-thing (car thing))
(display " . ")
(display-thing (cdr thing))
(display ")"))
(display thing)))
And now
> (display-thing (cons (cons 'a 'b) (cons 'c 'd)))
((a . b) . (c . d))
> (display-thing '((a . b) . (c . d)))
((a . b) . (c . d))
> (display-thing '((a . b) c . d))
((a . b) . (c . d))
What this should all be telling you is that ((a . b) . (c . d)) and ((a . b) c . d) are merely different ways of writing a structurally identical object.
Pairs visualize differently based on their content. If the cdr of a pair contains the empty list it is a proper list an dthe dot and extra empty list is not shown:
(cons 'a '())
'(a . ())
; ==> (a)
A pair that has pair as it's cdr can be visualized as a list element without the . and extra parenthesis:
(cons 'b '(a))
'(b . (a))
; ==> (b a)
(cons 'b '(a . c))
'(b . (a . c))
; ==> (b a . c)
These are just made so that we can have (1 2 3) displayed instead of (1 . (2 . (3 . ()))) which is how it really is made.
If you were to not have a pair or a empty list in the cdr then it falls back to showing the dotted pair:
(cons 'a 'b)
'(a . b)
; ==> (a . b)
In your example '((a . b) . (c . d)) because there is a pair after a dot (eg. the cdr if the pair the visualization will remove the dot and one pair of parentheses and show it like ((a . b) c . d). This is the only acceptable correct way for a REPL to display this even though both your example and the display will be read in as the same structure.
There is a similar issue with numbers. In code you can use 10, #xa and #o12 to get the number 10 and the value will have no idea what format is was read in as and only show the base 10 in the REPL.
;;; ```
;;; <- can one use cons to do ((a . b) . (c . d))?
(define x (cons a b)); nil -- should it be error
(define x (cons 'a 'b)); (a . b)
(define y (cons 'c 'd)); (c . d)
(define z00 (cons x y)) ; (((a . b) c . d) <- cannot use cons to do ((a . b) . (c . d))?
(define z01 (cons x 'y)) ; ((a . b) . y)
(define z10 (cons 'x y)) ; (x c . d)
(define z11 (cons 'x 'y)); (x . y))
(define z22 (cons '(f g) '(h i)))
(define z2c (cons (cons 'f 'g) (cons 'h 'i)))
(define fgc (cons ('f 'g))); should it be error (nil)
; actually not as 'f is an exoression (quote f) and f for some reason is nil it becomes nil from quote of nil abd so is the second one. now (nil . nil) is (nil)
(define z (list x y z00 z01 z10 z11 z22 z2c fgc))
; ((a . b) (c . d) ((a . b) c . d) ((a . b) . y) (x c . d) (x . y))
;;; ```
;;; and if not any other means or dot pair cannot have 2nd element like this?
;;; possibly not
;;; as the cons join 2 pairs of dotted pairs and can generate one dotted pair
;;; ((a . b) . (c . d)) but the printing rule is reflected the list bias
;;; this new dotted pair will have the first element as (( a . b) ... print as
;;; ((a . b) ...
;;; the 2nd element it will consider whether it is an atom or another dotted pair
;;; (other possibilities like loop back or something else ... not sure)
;;; as (c . d) is a dotted pair the "printing" continues as a list would
;;;
;;; ((a . b) c ...
;;; however the second element of (c . d) is not a dotted pair but an atom and print as
;;; . d) will it becomes
;;; hence even though you form the binary tree head the dot pair would display as a partial list
;;; you can have a list of dotted pairs like z
;;; but not dotted pair of dotted pairs

Currying a sum of squares function in Scheme

I am trying to curry a functions of 4 arguments in Scheme. This is what I have for my curry function. The output should be 30. Please help me with my curry4 function.
(define sum-of-squares
(lambda (a b c d)
(+ (* a a) (* b b) (* c c) (* d d))))
(define curry4
(lambda (a b c d)
(apply sum-of-squares (a (b (c (d)))))))
(((((curry4 sum-of-squares) 1) 2) 3) 4)
Here's something you can try:
(define (((((curry-4 func) a) b) c) d)
(func a b c d))
Note that this is special syntax for expanding it out like:
(define (curry-4 func)
(λ (a)
(λ (b)
(λ (c)
(λ (d) (func a b c d))))))
What we're doing here is returning a lambda that returns a lambda that ... returns a lambda that returns the result of applying func. Essentially, we're taking one argument at a time, and once we have all of them, we can give back the final value. Until then, we give back a function that's still waiting for the rest of the arguments.
In Racket just use curry. You can check definining file in DrRacket.
#lang racket
(define (f n1 n2 n3 n4)
(apply +
(map (λ (x) (expt x 2))
(list n1 n2 n3 n4))))
(((((curry f) 1) 2) 3) 4)
Currying by hand.
#lang racket
(define curry-by-hand-f
(lambda (x1)
(lambda (x2)
(lambda (x3)
(lambda (x4)
(f x1 x2 x3 x4))))))
((((curry-by-hand-f 1) 2) 3) 4)

Extended Euclidian Algorithm in Scheme

I'm trying to write a code for extended Euclidian Algorithm in Scheme for an RSA implementation.
The thing about my problem is I can't write a recursive algorithm where the output of the inner step must be the input of the consecutive outer step. I want it to give the result of the most-outer step but as it can be seen, it gives the result of the most inner one. I wrote a program for this (it is a bit messy but I couldn't find time to edit.):
(define ax+by=1
(lambda (a b)
(define q (quotient a b))
(define r (remainder a b))
(define make-list (lambda (x y)
(list x y)))
(define solution-helper-x-prime (lambda (a b q r)
(if (= r 1) (- 0 q) (solution-helper-x-prime b r (quotient b r) (remainder b r)))
))
(define solution-helper-y-prime (lambda (a b q r)
(if (= r 1) (- r (* q (- 0 q) )) (solution-helper-y-prime b r (quotient b r) (remainder b r))
))
(define solution-first-step (lambda (a b q r)
(if (= r 1) (make-list r (- 0 q))
(make-list (solution-helper-x-prime b r (quotient b r) (remainder b r)) (solution-helper-y-prime b r (quotient b r) (remainder b r))))
))
(display (solution-first-step a b q r))
))
All kinds of help and advice would be greatly appreciated. (P.S. I added a scrrenshot of the instructions that was given to us but I can't see the image. If there is a problem, please let me know.)
This is a Diophantine equation and is a bit tricky to solve. I came up with an iterative solution adapted from this explanation, but had to split the problem in parts - first, obtain the list of quotients by applying the extended Euclidean algorithm:
(define (quotients a b)
(let loop ([a a] [b b] [lst '()])
(if (<= b 1)
lst
(loop b (remainder a b) (cons (quotient a b) lst)))))
Second, go back and solve the equation:
(define (solve x y lst)
(if (null? lst)
(list x y)
(solve y (+ x (* (car lst) y)) (cdr lst))))
Finally, put it all together and determine the correct signs of the solution:
(define (ax+by=1 a b)
(let* ([ans (solve 0 1 (quotients a b))]
[x (car ans)]
[y (cadr ans)])
(cond ((and (= a 0) (= b 1))
(list 0 1))
((and (= a 1) (= b 0))
(list 1 0))
((= (+ (* a (- x)) (* b y)) 1)
(list (- x) y))
((= (+ (* a x) (* b (- y))) 1)
(list x (- y)))
(else (error "Equation has no solution")))))
For example:
(ax+by=1 1027 712)
=> '(-165 238)
(ax+by=1 91 72)
=> '(19 -24)
(ax+by=1 13 13)
=> Equation has no solution

Understanding map pattern for n-ary operations on n lists in Scheme

I understand that (map f '(a b c d)) is '(f(a) f(b) f(c) f(d)) by applying function f to each element in the list. But the following seems to be hard to understand for me:
(map * '(1 2) '(1 2))
The output should be '(1 4). How come?
Can anyone explain how map pattern works in Scheme when we apply an n-ary operation to n lists?
map takes the ith elements of the provided lists, passes them to the n-ary operation, and stores the result at ith position of the returned list.
So, (map f '(a b c d) '(A B C D)) will be equal to ((f a A) (f b B) (f c C) (f d D)).
More than two lists are handled similarly.
'(f (a) f (b) f (c) f (d)) is and can only be (f (a) f (b) f (c) f (d)) after evaluation.
map for one list argument can be defined like this:
(define (map1 fn lst)
(if (null? lst)
'()
(cons (fn (car lst))
(map1 fn (cdr lst)))))
and (map add1 '(1 2 3)) can be substituted with
(cons (add1 '1)
(cons (add1 '2)
(cons (add1 '3)
'())))
; ==> (2 . (3 . (4 . ())))
; ==> (2 3 4)
Now map takes at least one list argument and it expects the function passed to take one or each. Thus (map * '(1 2) '(1 2)) is the same as:
(cons (* '1 '1)
(cons (* '2 '2)
'()))
; ==> (1 . (4 . ()))
; ==> (1 4)
I'm not entirely sure if you are having trouble grasping map or how lists are made. If it is the latter you should really make it top priority to be able to see (1 2 (3 4)) and understand that 3 is the caaddr since the pairs are (1 . (2 . ((3 . (4 . ())) . ()))). Read it right to left while looking at the pairs and you see it. If it's map then you need to implement them. It is the best way to learn it.
To truly understand something is best to implement it ourselves.
The map for 1-argument functions is easy, it's
(define (map1 f1 xs)
(cons (f1 (car xs))
(map1 f1
(cdr xs))))
(adding the base case is left as an exercise). Similarly for two,
(define (map2 f2 xs ys)
(cons (f2 (car xs) (car ys))
(map2 f2
(cdr xs) (cdr ys))))
and three,
(define (map3 f3 xs ys zs)
(cons (f3 (car xs) (car ys) (car zs))
(map3 f3
(cdr xs) (cdr ys) (cdr zs))))
We can use the same template for any n-argument function to be mapped over any n lists to take the n arguments from:
map_n:
xs: x1 x2 x3 x4 x5 ...
ys: y1 y2 y3 y4 y5 ...
zs: z1 z2 z3 z4 z5 ...
...........................
↓ ↓ ↓ ↓ ↓
f f f f f
= = = = =
results: r1 r2 r3 r4 r5 ...
related: Matrix multiplication in scheme, List of lists

DrRacket/Scheme: not a procedure

I am trying to create program in Scheme (DrRacket) to solve roots of quadratic equation. I have also function to solve discriminant (function D). If discriminant is >0 function root should have on the output "point pair" (is that the correct word? english is not my native language) of both roots. Else it should give #f on the output.
(define na2
(lambda (x)
(* x x)))
(define D
(lambda (a b c)
(- (na2 b) (* 4 a c))))
(define roots
(lambda (a b c)
((if (> (D a b c) 0)
(cons (/ (+ (- b) (sqrt (D a b c))) (* 2 a)) (/ (- (- b) (sqrt (D a b c))) (* 2 a)))
#f)))
It gives me this:
> (roots 1 3 2)
>: contract violation
expected: real?
given: (-1 . -2)
argument position: 1st
other arguments...:
>
As you can see the correct output is there, but why the error?
Edit:
I corrected typo, as Parakram Majumdar helepd me, now it gives me
application: not a procedure;
expected a procedure that can be applied to arguments
given: (-1 . -2)
arguments...: [none]
Can someone please tell what am I doing wrong?
As discussed in the comments, the if statement should be written as follows:
(if cond then else)
where the condition would be :
(> (D a b c) 0)
So overall it should be:
(define roots
(lambda (a b c)
(if (> (D a b c) 0)
(cons (/ (+ (- b) (sqrt (D a b c))) (* 2 a))
(/ (- (- b) (sqrt (D a b c))) (* 2 a)))
#f
)))

Resources