lisp conditional call function - macros

How to write a macro "MAXF" : find max value in a parameter list , then call a specific function? e.g.
(defun func (x y z) (format t "~A ~A ~A~%" x y z))
(let ((a 1) (b 1))
(maxf ((+ a b 1) (func a b 1)) ((+ a b 2) (func a b 2))... ((+ a b 100)
(func a b 100)) )
The result should be: "1 1 100"

Related

(Chez) Scheme macro for hiding lambdas

I would like to write a macro to create shorthand syntax for hiding more verbose lambda expressions, but I'm struggling to understand how to write macros (which I realize is an argument against using them).
Given this example:
(define alist-example
'((x 1 2 3) (y 4 5 6) (z 7 8 9)))
(define ($ alist name)
(cdr (assoc name alist)))
((lambda (a) (map (lambda (x y z) (+ x y z)) ($ a 'x) ($ a 'y) ($ a 'z))) alist-example)
((lambda (a) (map (lambda (y) (/ y (apply max ($ a 'y)))) ($ a 'y))) alist-example)
I would like to write a macro, with-alist, that would allow me to write the last two expressions similar to this:
(with-alist alist-example (+ x y z))
(with-alist alist-example (/ y (apply max y)))
Any advice or suggestions?
Here is a syntax-rules solution based on the feedback that I received in the other answer and comments:
(define ($ alist name)
(cdr (assoc name alist)))
(define-syntax with-alist
(syntax-rules ()
[(_ alist names expr)
(let ([alist-local alist])
(apply map (lambda names expr)
(map (lambda (name) ($ alist-local name)) (quote names))))]))
Here is some example usage:
> (define alist-example
'((x 1 2 3) (y 4 5 6) (z 7 8 9)))
> (with-alist alist-example (x) (+ x 2))
(3 4 5)
> (with-alist alist-example (x y) (+ x y))
(5 7 9)
> (with-alist alist-example (x y z) (+ x y z))
(12 15 18)
This answer stops short of solving the more complicated example, (with-alist alist-example (/ y (apply max y))), in my question, but I think this is a reasonable approach for my purposes:
> (with-alist alist-example (y) (/ y (apply max ($ alist-example 'y))))
(2/3 5/6 1)
EDIT: After some additional tinkering, I arrived at a slightly different solution that I think will provide more flexibility.
My new macro, npl, expands shorthand expressions into a list of names and procedures.
(define-syntax npl
(syntax-rules ()
[(_ (names expr) ...)
(list
(list (quote names) ...)
(list (lambda names expr) ...))]))
The output of this macro is passed to a regular procedure, with-list-map, that contains most the core functionality in the with-alist macro above.
(define (with-alist-map alist names-proc-list)
(let ([names-list (car names-proc-list)]
[proc-list (cadr names-proc-list)])
(map (lambda (names proc)
(apply map proc
(map (lambda (name) ($ alist name)) names)))
names-list proc-list)))
The 3 examples of with-alist usage above can be captured in a single call to with-alist-map.
> (with-alist-map alist-example
(npl ((x) (+ x 2))
((x y) (+ x y))
((x y z) (+ x y z))))
((3 4 5) (5 7 9) (12 15 18))
The immediate problem I see is that there is no way to tell which bindings to pick. Eg. is apply one of the elements in the alist or is it a global variable? That depends. I suggest you do:
(with-alist ((x y z) '((x 1 2 3) (y 4 5 6) (z 7 8 9)))
(+ x y z))
(let ((z 10))
(with-alist ((x y) alist-example)
(+ x y z)))
And that it should translate to:
(let ((tmp '((x 1 2 3) (y 4 5 6) (z 7 8 9))))
(apply map (lambda (x y z) (+ x y z))
(map (lambda (name) ($ tmp name)) '(x y z))))
(let ((z 10))
(let ((tmp alist-example))
(apply map (lambda (x y) (+ x y z))
(map (lambda (name) ($ tmp name)) '(x y)))))
This is then straight forward to do with syntax-rules. Eg. make a pattern and write the replacement. Good luck.

Using built-in math operators with custom struct

I want to be able to do something like this:
(struct point (x y))
(define p1 (point 1 2))
(define p2 (point 10 20))
(+ p1 p2) ; -> (point 11 22)
Is it possible to teach a struct like point to work with built-in math operators like +?
The docs seem to manage to implement custom (equal? ...) handling in section 5.5 on this page. What I'm trying to do is quite similar ...
Or should I just define function like (point-add p1 p2)?
You can either
Go with point-add
Use your own + that matches against all possible value types that you want to take on. This is sufficient if you know all possible value types beforehand, but it wouldn't be easy to extend it to include newly created struct definitions in client's code. For example:
;; We will "shadow" Racket's + with our own +, but we still
;; need the functionality of Racket's +, so let's require
;; Racket's + but use the name racket:+ instead
(require (only-in racket/base [+ racket:+]))
(struct point (x y) #:transparent)
(define (+ x y)
(match* (x y)
[((point a b) (point c d)) (point (+ a c) (+ b d))]
[((point _ _) _) (error '+ "Can't add a point with non point")]
[(_ (point _ _)) (error '+ "Can't add a point with non point")]
[(_ _) (racket:+ x y)]))
;; in client's code
(+ (point 1 2) (point 3 4)) ;=> (point 4 6)
(+ 1 2) ;=> 3
Define a new generics so that we can do something similar to gen:equal+hash for equal?. For example:
(require racket/generic
(only-in racket/base [+ racket:+]))
(define-generics addable
(add addable _)
#:fast-defaults ([number?
(define (add x y) (racket:+ x y))]))
(define + add)
;; in client's code
(struct point (x y)
#:transparent
#:methods gen:addable
[(define (add x y)
(match* (x y)
[((point a b) (point c d)) (point (+ a c) (+ b d))]
[(_ _) (error 'add "Can't add a point with non point")]))])
(struct point-3d (x y z)
#:transparent
#:methods gen:addable
[(define (add x y)
(match* (x y)
[((point-3d a b c) (point-3d d e f))
(point-3d (+ a d) (+ b e) (+ c f))]
[(_ _) (error '+ "Can't add a point-3d with non point-3d")]))])
(+ (point 1 2) (point 3 4)) ;=> (point 4 6)
(+ (point-3d 1 2 3) (point-3d 4 5 6)) ;=> (point-3d 5 7 9)
(+ 1 2) ;=> 3
To accept multiple arguments, modify (3) as follows
(define +
(case-lambda
[() 0]
[(x . xs) (foldl add x xs)]))
;; client's code
(+ (point 1 2) (point 3 4) (point 5 6)) ;=> (point 9 12)
(+ 1 2 3) ;=> 6
(+) ;=> 0
(+ 1) ;=> 1
(+ (point-3d 1 2 3)) ;=> (point-3d 1 2 3)

Function composition in Scheme

I'm trying to modify the function below to compose two functions in Scheme.
(define (compose F1 F2)
(eval F1 (interaction-environment))
)
rather than
(define (compose f g)
(λ (x) (f (g x))))
But I'm not sure about how to use eval.
From your suggestion, I guess you want to use Scheme's macros / preprocessing capabilities. eval isn't meant for code transformation. Composition ∘ can be defined in Scheme as
(define (∘ f g)
(lambda (x) (f (g x))) )
or
(define-syntax ∘
(syntax-rules ()
((∘ f g)
(lambda (x) (f (g x))) )))
where the arity of expressions f and g is 1.
(define (plus-10 n) (+ n 10))
(define (minus-3 n) (- n 3))
(display
(map (∘ plus-10 minus-3)
(list 1 2 3 4) ))
The map expression at compile-time becomes
(map (lambda (x) (plus-10 (minus-3 x)))
(list 1 2 3 4) )
equal?s
(list 8 9 10 11)

Scheme Helper Function and always returning zero

I am trying to write a Scheme function that takes in a list of letters, hashes them with another function, multiplies each one iteratively by 5^i, and sums them together. I am new to Scheme and this is what I have written:
(define (key w)
keyhelper w 0)
(define (keyhelper w i)
(cond ((null? w) '())
(else (+ (* (hashchar(car w) (expt 5 i)) (keyhelper(cdr w) (+ i 1)))))))
So for example, doing (key '(h e l l o)) should do hashchar(h)*5^0 + hashchar(e)*5^1 + hashchar(l)^5^2 ... etc. The function is only returning 0 for any list that is sent in. Could anyone please tell me where I am going wrong?
My implementation of hashchar is:
(define hashchar
(lambda (x)
(cond
((eq? x 'a) 1)
((eq? x 'b) 2)
((eq? x 'c) 3)
((eq? x 'd) 4)
((eq? x 'e) 5)
((eq? x 'f) 6)
((eq? x 'g) 7)
((eq? x 'h) 8)
((eq? x 'i) 9)
((eq? x 'j) 10)
((eq? x 'k) 11)
((eq? x 'l) 12)
((eq? x 'm) 13)
((eq? x 'n) 14)
((eq? x 'o) 15)
((eq? x 'p) 16)
((eq? x 'q) 17)
((eq? x 'r) 18)
((eq? x 's) 19)
((eq? x 't) 20)
((eq? x 'u) 21)
((eq? x 'v) 22)
((eq? x 'w) 23)
((eq? x 'x) 24)
((eq? x 'y) 25)
((eq? x 'z) 26))))
key returns zero all the time because you defined it that way. You had:
(define (key w)
keyhelper
w
0)
thus, it evaluates keyhelper (discarding its value), then w (discarding its value), then 0 (returning its value). So the answer is always 0.
You should instead define it this way:
(define (key w)
(keyhelper w 0))
Notice the extra parentheses.
Also, the base-case value for keyhelper is wrong. It shouldn't be '(), it should be i.
If your definition of hashchar is similar to this one:
(define (hash:hash-char-ci char n)
(modulo (char->integer (char-downcase char)) n))
(define hash:hash-char hash:hash-char-ci)
Then hashchar will return 0 when i = 0 is passed to (expt 5 i) because (expt 5 i) is one, and the one-modulo of any integer is zero.
Once you multiply zero into your hash function, then you'll always get zero out...since + isn't doing anything but returning identity because it is only passed one argument:
(* (hashchar(car w) (expt 5 i)) (keyhelper(cdr w) (+ i 1)))
Maybe string-hash is a better choice of library function?

How would I express this Scheme function more clearly?

(define (repeated f n)
if (= n 0)
f
((compose repeated f) (lambda (x) (- n 1))))
I wrote this function, but how would I express this more clearly, using simple recursion with repeated?
I'm sorry, I forgot to define my compose function.
(define (compose f g) (lambda (x) (f (g x))))
And the function takes as inputs a procedure that computes f and a positive integer n and returns the procedure that computes the nth repeated application of f.
I'm assuming that (repeated f 3) should return a function g(x)=f(f(f(x))). If that's not what you want, please clarify. Anyways, that definition of repeated can be written as follows:
(define (repeated f n)
(lambda (x)
(if (= n 0)
x
((repeated f (- n 1)) (f x)))))
(define (square x)
(* x x))
(define y (repeated square 3))
(y 2) ; returns 256, which is (square (square (square 2)))
(define (repeated f n)
(lambda (x)
(let recur ((x x) (n n))
(if (= n 0)
args
(recur (f x) (sub1 n))))))
Write the function the way you normally would, except that the arguments are passed in two stages. It might be even clearer to define repeated this way:
(define repeated (lambda (f n) (lambda (x)
(define (recur x n)
(if (= n 0)
x
(recur (f x) (sub1 n))))
(recur x n))))
You don't have to use a 'let-loop' this way, and the lambdas make it obvious that you expect your arguments in two stages.
(Note:recur is not built in to Scheme as it is in Clojure, I just like the name)
> (define foonly (repeat sub1 10))
> (foonly 11)
1
> (foonly 9)
-1
The cool functional feature you want here is currying, not composition. Here's the Haskell with implicit currying:
repeated _ 0 x = x
repeated f n x = repeated f (pred n) (f x)
I hope this isn't a homework problem.
What is your function trying to do, just out of curiosity? Is it to run f, n times? If so, you can do this.
(define (repeated f n)
(for-each (lambda (i) (f)) (iota n)))