Is there a way to associate a character to a mathematical operator?
for example, if I can associate the letter "b" as addition then
(b 2 2)
Output
4
Is this possible? If so is there any material or examples I can use as a guide?
It's rather simple, look:
(define b +)
(b 2 2)
> 4
Now b is an alias for +. You can use the same idea for creating aliases for any procedure you want, with any name (it's not restricted to single-character names). Be aware that it won't work for other special forms; for instance this will produce an error:
(define my-and and)
The wording is a little off (take this as a friendly note).
In Scheme/Racket the mathematical functions +, -, *, etc. are not keywords as they are in many programming languages. They are simply names.
The expression + evaluates to a value, namely a function that can add numbers.
In order to introduce your own names for values, you can use define.
(define plus +)
Gives the name plus to the value resulting from evaluating +.
You can therefore give your own one-letter names, like
(define p +)
However one-letter names are not characters. Characters are what a string is made of.
Related
From my understanding, it is not legal to modify a list created using quote:
(let ((numbers '(3 2 1)))
(set-car! numbers 99) ; Illegal.
numbers)
What about lists created using quasiquote? Is it legal to modify lists created using quasiquote?
(let ((numbers `(3 2 1)))
(set-car! numbers 99) ; Legal?
numbers)
(let ((numbers `(,(+ 1 2) 2 1)))
(set-car! numbers 99) ; Legal?
numbers)
The short answer is no, this isn't "legal", and certainly this should never be done in a program that aims to be portable. R6RS and R7RS have almost identical language around this, so I'll just quote from R6RS, Section 11.17 Quasiquotation:
A quasiquote expression may return either fresh, mutable objects or literal structure for any structure that is constructed at run time during the evaluation of the expression. Portions that do not need to be rebuilt are always literal.
Section 4.2.8 of R7RS has the same language, except that it says "newly allocated" instead of "fresh".
Since it is an error to attempt to modify literals in Scheme, it is an error to modify the result of a quasiquote form. This is something that you may seem get away with sometimes, but it will bite you sooner or later. The real catch here is that "portions that do not need to be rebuilt are always literal". Other portions may or may not be literal.
More specifically for OP posted code, `(3 2 1) is guaranteed to evaluate to a list literal by the semantics of quasiquote described in Section 11.17 of R6RS:
Semantics: If no unquote or unquote-splicing forms appear within the <qq template>, the result of evaluating (quasiquote <qq template>) is equivalent to the result of evaluating (quote <qq template>).
R7RS contains similar language in Section 4.2.8. Since (quote (3 2 1)) creates a list literal, the expression `(3 2 1) must also evaluate to a list literal.
On the other hand, OP code `(,(+ 1 2) 2 1) must evaluate (+ 1 2) and insert that result into the resulting structure. In this case, unquote is used via the , operator, so the resulting list structure may or may not be a list literal.
To take one more example, consider the quasiquoted expression `(,(+ 1 2) (2 1)). Here the main result is a list structure which may or may not be a list literal, but the element (2 1) of the resulting structure is guaranteed to be a list literal since it does not need to be rebuilt in the construction of the final result.
(define (prime max)
(let ((a 2)))
(if not(= modulo max 2) 0)
((+ a 1)
prime(max))
)
It tells me bad let in form (let ((a 2))) but as far as I'm aware, the syntax and code is right
No, it is not right. let form has this syntax: (let binds body) Your bindings are ((a 2)). Where's your body? You put it outside the let form. This raises two problems: let is malformed by only having one argument instead of two, and a is undeclared at the location it appears in. (Without going into the logic of the code, which is also incorrect, assuming you are trying for a primality test function.)
let format is
(let ((<var1> <value1>)
(<var2> <value2>)
...
(<varN> <valueN>))
<expr1>
<expr2>
...
<exprN>)
Also the general form for calling a function is
(<function> <arg1> <arg2> ... <argN>)
so your not call is wrong, should be (not ...) and the call to prime should have the form (prime max).
You got the addition "operator" (+ a 1) correct but indeed one big difference between Lisp dialects and other languages is that you don't have special operators, just functions. (+ a 1) is just like (add a 1): you are just calling a function that is named +; no special unary prefix/postfix case or precedence and associativity rules... just functions: not is a function + is a function.
Lisp "syntax" may feel weird at first (if and because you've been exposed to other programming languages before), but the problem doesn't last long and after a little all the parenthesis just disappear and you begin to "see" the simple tree structure of the code.
On the other spectrum of syntax complexity you've for example C++ that is so complex that even expert programmers and compiler authors can debate long just about how to interpret and what is the semantic meaning of a given syntax construct. Not kidding there are C++ rules that goes more of less "if a syntax is ambiguous and could be considered both as a declaration and as an expression, then it's a declaration" (https://en.wikipedia.org/wiki/Most_vexing_parse). Go figure.
Is it possible to quote result of function call?
For example
(quoteresult (+ 1 1)) => '2
At first blush, your question doesn’t really make any sense. “Quoting” is a thing that can be performed on datums in a piece of source code. “Quoting” a runtime value is at best a no-op and at worst nonsensical.
The example in your question illustrates why it doesn’t make any sense. Your so-called quoteresult form would evaluate (+ 1 1) to produce '2, but '2 evaluates to 2, the same thing (+ 1 1) evaluates to. How would the result of quoteresult ever be different from ordinary evaluation?
If, however, you want to actually produce a quote expression to be handed off to some use of dynamic evaluation (with the usual disclaimer that that is probably a bad idea), then you need only generate a list of two elements: the symbol quote and your function’s result. If that’s the case, you can implement quoteresult quite simply:
(define (quoteresult x)
(list 'quote x))
This is, however, of limited usefulness for most programs.
For more information on what quoting is and how it works, see What is the difference between quote and list?.
I'm going through this Scheme tutorial and in section 3 (Making Lists) the guy says you should write '() to represent an empty list. But for every test I've wrote seems that it has the very same effect as using just ().
Also, as far as I understand, the quote means the interpreter won't evaluate the expression, but seems that the interpreter knows what's after the ' symbol, because doing this (cons 1 '()) yields (1), while doing this (cons 1 'abc) yields (1 . abc), so it knows '() is an empty list but 'abc is not.
Some Scheme implementations permit bare () as a synonym for '(), but only the quoted form is standard.
As for your second question: consider
(define abc '(1 2 3))
(define def '(1 2 3))
(cons 0 'abc)
(cons 0 'def)
(cons 0 abc)
(cons 0 def)
In the first two expressions, abc and def are not evaluated, so they stay symbols. In the latter two, they are evaluated to the objects they stand for, which are both equal to the list (1 2 3).
TL;DR: To make sure your applications work as as designed you should quote the empty list since it's unsure if it will work otherwise. see the long answer below.
As for how Scheme works for quoted values, quoting '(+ 3 4 5) makes an expression a constant that is not to be evaluated. It much like making a string with code in it, like "if( a == 0 ) return 4;" in Java or C. The difference is that a quoted expression are structured data rather than byte sequences.
(cons 1 'abc) and (cons 1 '()) does the same. A cons has two placeholders for values and those two expressions sets two values in the exact same manner. It's only display (and the repl) that knows that a list that ends with () should display differently and not (1 . ()) like it actually is stored.
The long answer about the need to quote the empty list
It all boils down to the standard you're using. Most implementations today are R5RS and it requires the empty list be quoted since the empty list is not an expression. Implementations might still allow it though since it won't interfere with a proper Scheme application. Heres a quote from the R5RS report:
Note: In many dialects of Lisp, the empty combination, (), is a
legitimate expression. In Scheme, combinations must have at least one
subexpression, so () is not a syntactically valid expression.
This actually happened in R3RS (under Procedure calls) so it's been around for a while. When looking for it in R6RS however it seems to have disappeared from the section making me think they have reverted it so that it would be self evaluating. However, I cannot find it in the language changes part.
When looking at the R7RS draft (NB: PDF), the part from R5RS is back so I guess this was an error in the R6RS report. This might be the reason racket (and probably other implementors) allow () as an expression in R6RS to be sure it will work even when the report is ambiguous about it.
I've looked through On Lisp, Practical Common Lisp and the SO archives in order to answer this on my own, but those attempts were frustrated by my inability to name the concept I'm interested in. I would be grateful if anyone could just tell me the canonical term for this sort of thing.
This question is probably best explained by an example. Let's say I want to implement Python-style list comprehensions in Common Lisp. In Python I would write:
[x*2 for x in range(1,10) if x > 3]
So I begin by writing down:
(listc (* 2 x) x (range 1 10) (> x 3))
and then defining a macro that transforms the above into the correct comprehension. So far so good.
The interpretation of that expression, however, would be opaque to a reader not already familiar with Python list comprehensions. What I'd really like to be able to write is the following:
(listc (* 2 x) for x in (range 1 10) if (> x 3))
but I haven't been able to track down the Common Lisp terminology for this. It seems that the loop macro does exactly this sort of thing. What is it called, and how can I implement it? I tried macro-expanding a sample loop expression to see how it's put together, but the resulting code was unintelligible. Could anyone guide me in the right direction?
Thanks in advance.
Well, what for does is essentially, that it parses the forms supplied as its body. For example:
(defmacro listc (expr &rest forms)
;;
;;
;; (listc EXP for VAR in GENERATOR [if CONDITION])
;;
;;
(labels ((keyword-p (thing name)
(and (symbolp thing)
(string= name thing))))
(destructuring-bind (for* variable in* generator &rest tail) forms
(unless (and (keyword-p for* "FOR") (keyword-p in* "IN"))
(error "malformed comprehension"))
(let ((guard (if (null tail) 't
(destructuring-bind (if* condition) tail
(unless (keyword-p if* "IF") (error "malformed comprehension"))
condition))))
`(loop
:for ,variable :in ,generator
:when ,guard
:collecting ,expr)))))
(defun range (start end &optional (by 1))
(loop
:for k :upfrom start :below end :by by
:collecting k))
Apart from the hackish "parser" I used, this solution has a disadvantage, which is not easily solved in common lisp, namely the construction of the intermediate lists, if you want to chain your comprehensions:
(listc x for x in (listc ...) if (evenp x))
Since there is no moral equivalent of yield in common lisp, it is hard to create a facility, which does not require intermediate results to be fully materialized. One way out of this might be to encode the knowledge of possible "generator" forms in the expander of listc, so the expander can optimize/inline the generation of the base sequence without having to construct the entire intermediate list at run-time.
Another way might be to introduce "lazy lists" (link points to scheme, since there is no equivalent facility in common lisp -- you had to build that first, though it's not particularily hard).
Also, you can always have a look at other people's code, in particular, if they tries to solve the same or a similar problem, for example:
Iterate
Loop in SBCL
Pipes (which does the lazy list thing)
Macros are code transformers.
There are several ways of implementing the syntax of a macro:
destructuring
Common Lisp provides a macro argument list which also provides a form of destructuring. When a macro is used, the source form is destructured according to the argument list.
This limits how macro syntax looks like, but for many uses of Macros provides enough machinery.
See Macro Lambda Lists in Common Lisp.
parsing
Common Lisp also gives the macro the access to the whole macro call form. The macro then is responsible for parsing the form. The parser needs to be provided by the macro author or is part of the macro implementation done by the author.
An example would be an INFIX macro:
(infix (2 + x) * (3 + sin (y)))
The macro implementation needs to implement an infix parser and return a prefix expression:
(* (+ 2 x) (+ 3 (sin y)))
rule-based
Some Lisps provide syntax rules, which are matched against the macro call form. For a matching syntax rule the corresponding transformer will be used to create the new source form. One can easily implement this in Common Lisp, but by default it is not a provided mechanism in Common Lisp.
See syntax case in Scheme.
LOOP
For the implementation of a LOOP-like syntax one needs to write a parser which is called in the macro to parse the source expression. Note that the parser does not work on text, but on interned Lisp data.
In the past (1970s) this has been used in Interlisp in the so-called 'Conversational Lisp', which is a Lisp syntax with a more natural language like surface. Iteration was a part of this and the iteration idea has then brought to other Lisps (like Maclisp's LOOP, from where it then was brought to Common Lisp).
See the PDF on 'Conversational Lisp' by Warren Teitelmann from the 1970s.
The syntax for the LOOP macro is a bit complicated and it is not easy to see the boundaries between individual sub-statements.
See the extended syntax for LOOP in Common Lisp.
(loop for i from 0 when (oddp i) collect i)
same as:
(loop
for i from 0
when (oddp i)
collect i)
One problem that the LOOP macro has is that the symbols like FOR, FROM, WHEN and COLLECT are not the same from the "COMMON-LISP" package (a namespace). When I'm now using LOOP in source code using a different package (namespace), then this will lead to new symbols in this source namespace. For that reason some like to write:
(loop
:for i :from 0
:when (oddp i)
:collect i)
In above code the identifiers for the LOOP relevant symbols are in the KEYWORD namespace.
To make both parsing and reading easier it has been proposed to bring parentheses back.
An example for such a macro usage might look like this:
(iter (for i from 0) (when (oddp i) (collect i)))
same as:
(iter
(for i from 0)
(when (oddp i)
(collect i)))
In above version it is easier to find the sub-expressions and to traverse them.
The ITERATE macro for Common Lisp uses this approach.
But in both examples, one needs to traverse the source code with custom code.
To complement Dirk's answer a little:
Writing your own macros for this is entirely doable, and perhaps a nice exercise.
However there are several facilities for this kind of thing (albeit in a lisp-idiomatic way) out there of high quality, such as
Loop
Iterate
Series
Loop is very expressive, but has a syntax not resembling the rest of common lisp. Some editors don't like it and will indent poorly. However loop is defined in the standard. Usually it's not possible to write extentions to loop.
Iterate is even more expressive, and has a familiar lispy syntax. This doesn't require any special indentation rules, so all editors indenting lisp properly will also indent iterate nicely. Iterate isn't in the standard, so you'll have to get it yourself (use quicklisp).
Series is a framework for working on sequences. In most cases series will make it possible not to store intermediate values.