Elisp: referencing previous variables inside let [duplicate] - elisp

This question already has an answer here:
in elisp's let, how do you reference a variable bound in the same let while binding another variable?
(1 answer)
Closed 8 years ago.
I'd like to define two variables in let, one of which depends on the value of the other, like so:
(let ((a (func))
(b (if (eq a 1) 2 3)))
...)
Obviously this is not the right way to do this, emacs says a is void.
What's the right way to do this?

Yes, you need to use let* instead of let.
Essentially, let* is a shortcut for nested lets:
(let ((a 1))
(let ((b (1+ a)))
(let ((c (* 2 b)))
...)))
is equivalent to
(let* ((a 1)
(b (1+ a))
(c (* 2 b)))
...)

Related

Both (funcall (lambda and (lambda worked

I am reading Simple-Lambda in elisp docs with an example
#+begin_src emacs-lisp :session sicp :lexical t
(funcall (lambda (a b c) (+ a b c))
1 (* 2 3) (- 5 4))
#+end_src
#+RESULTS:
: 8
the below works as well
#+begin_src emacs-lisp :session sicp :lexical t
((lambda (a b c) (+ a b c))
1 (* 2 3) (- 5 4))
#+end_src
#+RESULTS:
: 8
This confused me, elisp is lisp-2 style, so when evaluate (lambda (a b c) (+ a b c)), the interpreter will look into the block's cell for definition object, and thus the doc's demonstration make sense to invoke funcall
(funcall (lambda (a b c) (+ a b c))
1 (* 2 3) (- 5 4))
Nonetheless, it works without funcall?
((lambda (a b c) (+ a b c))
1 (* 2 3) (- 5 4))
Additionally, lambda is not of self-evaluating forms
It is common to write numbers, characters, strings, and even vectors
in Lisp code, taking advantage of the fact that they self-evaluate.
Elisp has a special case for lambda forms being called directly.
((lambda ...) ...)
As you've noted, that approach doesn't work in more general cases for other function-returning forms. It is also deprecated for this case where it does work, so it's best not to use it at all.
This syntax is covered briefly in (elisp)Function Indirection:
the following example calls a function without any
symbol function indirection, because the first element is an anonymous
Lisp function, not a symbol.
((lambda (arg) (erste arg))
'(1 2 3))
⇒ 1
Executing the function itself evaluates its body; this does involve
symbol function indirection when calling ‘erste’.
This form is rarely used and is now deprecated. Instead, you should
write it as:
(funcall (lambda (arg) (erste arg))
'(1 2 3))
or just
(let ((arg '(1 2 3))) (erste arg))

How to use double do loop in Scheme?

I want to use "do" command to show(1 1)(1 2)(1 3)(2 1)(2 2)(2 3)(3 1)(3 2)(3 3)
and my code is below:
(lambda ( )
(define a 1)
(define b 1)
(do ((a 1 (+ a 1))) (= a 3)
(do ((b 1 (+ b 1))) (= b 3)
(display a b)
)))
But this only show3as the result. Did I do something wrong? How should I correct it?
To Michael Vehrs,
Thank a lot, it really works! But I'm still confusing about the exit condition. I tried to change the>in your code to=and it shows(1 1)(1 2)(2 1)(2 2). Is it because it stops when a = 3 so it won't print?
So "list" command can combine several variables. But how about "newline" command? I tried to remove it and it just add another () in the last.
Thank you for the answer. I'm a new Scheme learner trying to use it on TracePro. Do you have any tip(book, Youtube video, website) for me about learning Scheme? Any advise would help.
A do loop is just syntax sugar for a recursive function. You might as well get used to write it directly. Here is a way to do it with one named let with two variables and an accumulator.
(let loop ((a 3) (b 3) (acc '()))
(cond ((zero? a) acc) ; finished
((zero? b) (loop (sub1 a) 3 acc)) ; b finsihed, reduce a and reset b
(else (loop a (sub1 b) (cons (list a b) acc))))) ; reduce b and add to front of acc
; ==> ((1 1) (1 2) (1 3) (2 1) (2 2) (2 3) (3 1) (3 2) (3 3))
Notice this makes the result in reverse order so it's optimal for lists that always are created in reverse order since that only can add new element in front.
You mean:
(lambda ()
(do ((a 1 (+ a 1)))
((> a 3) (newline))
(do ((b 1 (+ b 1)))
((> b 3))
(display (list a b))))))
Your code has a number of problems: The exit condition for the do loop is incorrect (and makes your procedure return 3). display takes a single object and an optional port as arguments. Defining your variables a and b is unnecessary, since the do construct defines new loop variables anyway.

Inputing pairs into an equation for Scheme

I'm trying to take two pairs '(a . b) '(c . d) and input them into an equation.
(define dist
(lambda (pr)
(sqrt (+ (expt (- (car pr) (car pr) 2)(expt (- (cdr pr) (cdr pr) 2)))
I tried this and a few other ways but I just get errors.
My actual equation seems to work with numbers but I'm not sure how I'm supposed to go about inputting two pairs, or if I'm even supposed to use an equation like the one I have.
I'm worried I'm thinking about this all wrong and nothing in my book mentions how to deal with two pairs and my teacher won't answer. I'm so confused, any tips or explanations would be wonderful.
EDIT:
I should've mentioned that to test my code I have numbers in place of the letters in the pairs for example:
(dist '(2 . 5) '(3 . 1))
I was trying to make it universal since any number has to be able to work with the code. Sorry for the confusion.
Example procedure:
(lambda (a b)
(+ a b))
Here a and b are two arguments. Their names are declared in the formal parameter list and they are used by those names in the body. That a and b might be numbers can only be seen by how they are used in the body of the procedure, but the formal parameter list itself doesn't say anything about type. They could be pairs and + might be lexically bound procedure that does something completely different than adding numbers.
In your procedure you have defined one bound variable pr. This seems from the code to be a pair since you are applying both car and cdr to it. If you need to add another pair you must add it to the formal parameter list with a name of your choosing (like pr perhaps was) and use that name in the procedure body.
You can read more about the format of lambda expressions in the R6RS standard.
You've shown a function dist that accepts two arguments:
(dist '(2 . 5) '(3 . 1))
where the first argument is '(2 . 5) and the second argument is '(3 . 1). But, your defined a function dist that accepts one argument that you've named pr. That won't work - one argument definition but two argument application.
How about:
(define dist
(lambda (arg1 arg2)
(let ((x1 (car arg1))
(y1 (cdr arg1))
(x2 (car arg2))
(y2 (cdr arg2)))
(sqrt (+ (expt (- x2 x1) 2)
(expt (- y2 y1) 2))))))

Issues with evaluating expressions from user input

I'm trying to make a recursive definition that reads and execute user expressions, such as (3 + 5). Everything is working, except of one problem with the arithmetic symbol.
I managed to replicate the error in a simpler example:
(define v '(1 + 3))
((cadr v) 2 4)
The (cadr v) is the + symbol, but for some reason the procedure can't be executed on the two arguments that followed. Am I missing something?
I think that's because
(cadr v)
returns '+ not + (literal + not a + function).
You need to evaluate it before applying it to arguments.
This should work:
((eval (cadr v)) 2 4)
^evaluates the '+ to +
edit
This worked in racket in interactive mode.
I'm not really sure what's the difference, but made it work in r5rs mode in racket (a script):
#lang r5rs
;required by r5rs
(define user-initial-environment (scheme-report-environment 5))
(define v '(1 + 2))
;eval expects a quoted expression
;(it seems that if it's a function it has to have arguments too)
;and evaluation environment.
((eval (cadr v) user-initial-environment) 2 4)
As others have pointed out, the problem is that the list you've constructed contains the symbol plus, rather than the function plus.
At its heart, this is the same reason that '(a b) returns a list of two symbols, rather than signalling an unbound identifier error; the quote starts a term in a "data language" where legal identifiers are interpreted as symbols, rather than as variable references.
The question, of course, is what you should do about it. Some here have suggested using 'eval'; this is probably a bad idea, for reasons that I think Matthew Flatt captures elegantly in his blog post on the topic.
Instead, you should probably write a simple mapping function. Here's the way I'd write it. If you use my code in an assignment, be sure to credit me :).
#lang racket
;; a mapping from symbols to operators
(define operator-hash
(hash '+ +
'- -
'* *))
;; ... and whatever other operators you want.
;; example of using it:
(hash-ref operator-hash '+) ;; ==> +
Try this:
(define v '(1 + 3))
(let ((operator (eval (cadr v)))
(operand1 (car v))
(operand2 (caddr v)))
(apply operator (list operand1 operand2)))
You can do it this way with eval in Guile:
(define (infix-eval v)
(eval (list (cadr v)(car v)(caddr v))
(interaction-environment)))
> (infix-eval '(1 + 2))
3
Rather than using interaction-environment, you could supply another environment for evaluation, where you could also define some other symbols not found in standard Scheme, so that expressions like (7 % 3) and (2 ^ 6) would also work.

Using let in Scheme

I want to write a program to find the roots of the quadratic equation in Scheme. I used LET for certain bindings.
(define roots-with-let
(λ (a b c)
(let ((4ac (* 4 a c))
(2a (* 2 a))
(discriminant (sqrt ( - (* b b) (4ac)))))
(cons ( / ( + (- b) discriminant) 2a)
( / ( - (- b) discriminant) 2a)))))
I defined the discriminant with 4ac since I did not want (* 4 a c). Even though I have defined (4ac (* 4 a c)), it is giving me this error:
expand: unbound identifier in module in: 4ac.
My question is how is let evaluated (what order)? And if i want 4ac in my let should i write another inner let? Is there a better way to do this?
Use let* instead of let.
The difference between let and let* is the following:
let* binds variables from left to right. Earlier bindings can be used in new binding further to the right (or down).
let on the other hand can be thought of as syntactic sugar (or macro) for simple lambda abstraction:
(let ((a exp1)
(b exp2))
exp)
is equivalent to
((lambda (a b)
exp)
exp1 exp2)
4ac is a variable with a numeric value, so (4ac) is not meaningful.
LET binds all variables, but the variables can't be used in the computations for the values.
This does not work:
(let ((a 1) (b 1) (c (* a b)))
c)
Use:
(let ((a 1) (b 1))
(let ((c (* a b)))
c))
Above introduces A and B with the first LET. In the second LET both A and B now can be used to compute C.
Or:
(let* ((a 1) (b 1) (c (* a b)))
c)
You'll need a special let-construct (let*) here since the variables inside the let-definition refer to each other.
It's rather a problem of defining a scope than of evaluating an expression (In usual let-definitions, the order of evaluation doesn't matter since the values may not use each other)
When you use let, the bindings are not visible in any of the bodies. Use let* instead and see the RNRS docs for details.

Resources