To enhance efficiency of my Lisp program, I want to insert this line into my code:
(optimize (speed 3) (safety 0) (debug 0) (space 0))
Currently I think I should put it at the top of each file. Is it a good idea or should I insert this line in one specific place? (I use ASDF for system definition.)
Another part of my question: is (safety 0) safe? Few of my functions use explicit declarations of variable types, what will happen to the others? Should I omit (safety 0) to avoid problems that might occur due to missing type-checking?
I would avoid setting compilation policies globally, since "as with other defining macros, it is unspecified whether or not the compile-time side-effects of a declaim persist after the file has been compiled". If you really want to use a global policy per file, you can use the locally special form at top-level (subforms of a top-level locally remain top-level forms)
(locally (declare (optimize speed #| ... whatever ... |#))
(defun compute-foo (x)
(1+ x))
(defun compute-bar (y)
(* (compute-foo y) y)))
instead of
(declaim (optimize speed #| ... whatever ... |#))
...
or even
(proclaim '(optimize speed #| ... whatever ... |#))
I tend to use declarations sparingly, usually only local within a function, i.e.,
(defun compute-foo (x)
(declare (fixnum x))
(1+ x))
Many modern Lisp compilers (like SBCL) have become pretty good at figuring types out. Further, I'd never use (safety 0) globally, since it may be dangerous, in particular during development, when things haven't really settled down and mistakes are common.
Related
Suppose we redefine the standard procedure car using one of the following:
(define (car)
(display "vroom vroom!"))
or
(set! car
(lambda ()
(display "vroom vroom!")))
Is it possible that in a standards compliant Scheme implementation, redefining car in this manner would affect the behavior of other standard procedures that happen to be defined using car?
For example, is a Scheme implementation allowed to internally define cadr as (define (cadr x) (car (cdr x))) such that a redefinition of car by the user at the REPL would change the behavior of cadr at the REPL?
There are different answers for different revisions.
R5RS and earlier:
You are not allowed to define existing bindings. Thus your first attempt is not correct Scheme according to the report and the result of running it can be anything. Eg. a segfault is ok, signaling an error is ok, ignoring it is ok.
You are only allowed to set a top level binding, but it needs to be backwards compatible with the original binding. Eg. It is not allowed to define car the way you do, but this is allowed:
(let ((orig-car car))
(set! car
(lambda (o)
(if (vector? o)
(vector-ref o 0)
(orig-car o)))))
(car '(1 2 3)) ; ==> 1
(car (vector 1 2 3)) ; ==> 1
The implementation is free to constant fold and compile. Thus in reality it might never use your new version, but the report does not stop the implementation from implementing cadr the way you wrote it and will then use the new implementation of car. As long as you keep to the standard and make it compatible the result is predictable.
R6RS and later:
From R6RS we have libraries and we can rename in and out and overriding it will not leak over in other libraries. Thus you can set! car, but it will not leak over so that cadr will start using it even if that is the way the implementation did cadr. This voids the need for it to be backwards compatible as well.
Usually you can make your own list library and in you code refrain from using the standard but rather your new version and it will use that. The link is rather static (you import explicit) so the bindings are never confused with the standard library ones.
No. The first example ((define (car) ...) binds "car" to a new location, shadowing the standard binding. In implementation uses of "car" ((define (cadr x) ...), "car" has its original binding.
(set! car ..., with "car" having its standard binding, must signal an error:
% scheme
Chez Scheme Version 9.5.7.6
Copyright 1984-2021 Cisco Systems, Inc.
> (display car)
#<procedure car>
> (set! car cdr)
Exception: attempt to assign immutable variable car
Search for "immutable" in a standard report, eg r6rs: "All explicitly exported variables are immutable in both the exporting and importing libraries." (So the base library cannot export a mutable car)
Yes. The behavior of the full system can be changed. But not how you did.
% mit-scheme
MIT/GNU Scheme running under GNU/Linux
....
1 ]=> (pe)
;Value: (user)
1 ]=> (ge system-global-environment)
;Package: ()
;Value: #f
1 ]=> (pe)
;Value: ()
1 ]=> (define + 1)
;Value: +
Move back to user environment (which is the same environment where initial REPL environment points to).
1 ]=> (ge user-initial-environment)
;Package: (user)
;Value: #[environment 12]
1 ]=> (pe)
;Value: (user)
1 ]=> (+ 1 2) ; no more
;The object 1 is not applicable.
;To continue, call RESTART with an option number:
; (RESTART 2) => Specify a procedure to use in its place.
; (RESTART 1) => Return to read-eval-print level 1.
2 error> (assoc 'car
(environment-bindings
system-global-environment))
;Value: (car #[compiled-procedure 1351
("list" #x1) #x1c #xe0f67c])
So you can change the CAR (which is defined in system-global-environment) in the same way I changed the +.
But, of course, this is a bad idea, your system won't work any more.
There are some internal procedures that are using car or +, which are compiled. Those that are compiled won't make reference to the system-global-environment and continue to work. Those that are not compiled will crash. Now, depends on how your system was booted, to see which ones make reference to the system env. If some library procedures are loaded in the system without compilation, it is for sure to crash.
Note that when I say "compilation", it means in general other way of interpretation other than calling the interpret/eval function, it means to bypass the standard interpreter. If you use a byte-compiler whose virtual machine makes reference to system environment, that procedure compiled as bytecode will crash. If the code is fully compiled to x86 or mips, it has its own referenced to standard library procedures written in assembler and it won't make reference to global environment. Everything is possible in a scheme system.
If you re-define the procedure in the user-environment (as you did), the system will continue working, as the standard library procedures point to the system environment and no system procedure will see the user environment. But all the procedures that you load in the user-environment will use your own definition of car. In this case, it is okay to redefine the things.
Note that the command (load "xxx") has an optional argument called environment and you can use this option to tell load what environment to change by loading to. By default, in batch-mode and REPL mode, load will write into the user-environment whose parent is system-env. But you can do tricks as the library load-option does, and manipulate environments into a very complex way (a library that creates modules).
Is the printf command a sensible way to attempt a debug or other techinuqes would be faster and/or more precise?
(Assume that I'm using Racket or other dialects that allow printf).
First off. Scheme (R7RS, R6RS, R5RS) doesn't have printf. There is display and SRFI-28 format. Because of this I'll just read printf as print statement which again could mean you're just using display.
The correct answer is that your code should be made into small procedures that can be unit tested easily. If you do that you'll never need either a debugger or printing out debug info ever again.
Usually Scheme uses expressions and it's not always easy to just add a print statement without having to wrap it and the following statement in a begin. Because of that you may introduce bugs when you add and, even worse, remove debug information from your code. eg.
(if (test arg)
(call-something (car arg))
(call-something-else (cdr arg))
So how much would you have to change in order to print the result of (test arg) without altering the course of the code and how easy would it be to remove that without introducing a new bug? If I really wanted to print out debug info I would have made a macro:
(define-syntax dbg
(syntax-rules ()
((_ . rest)
(let ((expr 'rest)
(res rest))
(display (list expr '=> res))
res))))
Now you could just prefix dbg where you want to inspect:
(if (dbg test arg)
(call-something (car arg))
(call-something-else (cdr arg))
Imagine that the result og (test arg) is 5, then you'll get ((test arg) => 5) out without altering the result to if.
If you happen to use DrRacket it's very simple to use the very good debugger and macro stepper which they have. With it you'll just set a break point and run towards the interesting parts and step through as you see the values every step calculates. There are probably some other IDEs as well but I stopped looking after I found racket. Even when using DrRacket nothing is keeping you from using a different implementation in production, like Ikarus, provided that you write in one of the Scheme reports and not something implementation specific.
Be careful! People who are too comfortable with debuggers tend to make long procedures that look more like FORTRAN than Scheme. The best is to write programs as if you didn't have any means of debugging, use the debugger when you feel the need and refactor your code if you find yourself in the debugger all the time.
How the scheme compiler determines, which functions will be available during macroexpansion?
I mean such low level mechanisms, like syntax-case, where you can not only generate patter substitution, but call some functions, at least in a fender part
Edit:
I mean, I need to use an ordinary function in macroexpansion process. E. g.:
(define (twice a)
(declare 'compile-time)
(* 2 a))
(let-syntax ((mac (lambda (x)
(syntax-case x ()
((_ n) (syntax (display (unsyntax (twice n)))))))))
(mac 4))
Where n is known to be a number, and evaluation of (twice n) occurs during expansion.
Every Scheme compiler determines the functions referenced by a macro expansion. In your case, the compilation of 'let-syntax' will result in the compiler determining that 'twice' is free (syntactically out-of-scope within 'let-syntax'). When the macro is applied, the free reference to the 'twice' function will have been resolved.
Different Scheme compilers perform the free value resolution at possibly different times. You can witness this by defining 'twice' as:
(define twice
(begin (display 'bound')
(lambda (x) (* 2 x))))
[In your case, with let-syntax it will be hard to notice. I'd suggest define-syntax and then a later use of '(mac 4'). With that, some compilers (guile) will print 'bound' when the define-syntax is compiled; others (ikarus) will print 'bound' when '(mac 4)' is expanded.]
It depends what macro system you are using. Some of these systems allow you to call regular scheme functions during expansion. For example, Explicit Renaming Macros let you do this:
(define-syntax swap!
(er-macro-transformer
(lambda (form rename compare?)
...
`(let ((tmp ,x))
(set! ,x ,y)
(set! ,y tmp)))))
That said, the macro systems available to you will depend upon what Scheme you are using.
I've been studying Scheme recently and come across a function that is defined in the following way:
(define remove!
(let ((null? null?)
(cdr cdr)
(eq? eq?))
(lambda ... function that uses null?, cdr, eq? ...)
What is the purpose of binding null? to null? or cdr to cdr, when these are built in functions that are available in a function definition without a let block?
In plain R5RS Scheme, there is no module system -- only the toplevel. Furthermore, the mentality is that everything can be modified, so you can "customize" the language any way you want. But without a module system this does not work well. For example, I write
(define (sub1 x) (- x 1))
in a library which you load -- and now you can redefine -:
(define - +) ; either this
(set! - +) ; or this
and now you unintentionally broke my library which relied on sub1 decrementing its input by one, and as a result your windows go up when you drag them down, or whatever.
The only way around this, which is used by several libraries, is to "grab" the relevant definition of the subtraction function, before someone can modify it:
(define sub1 (let ((- -)) (lambda (x) (- x 1))))
Now things will work "more fine", since you cannot modify the meaning of my sub1 function by changing -. (Except... if you modify it before you load my library...)
Anyway, as a result of this (and if you know that the - is the original one when the library is loaded), some compilers will detect this and see that the - call is always going to be the actual subtraction function, and therefore they will inline calls to it (and inlining a call to - can eventually result in assembly code for subtracting two numbers, so this is a big speed boost). But like I said in the above comment, this is more coincidental to the actual reason above.
Finally, R6RS (and several scheme implementations before that) has fixed this and added a library system, so there's no use for this trick: the sub1 code is safe as long as other code in its library is not redefining - in some way, and the compiler can safely optimize code based on this. No need for clever tricks.
That's a speed optimization. Local variable access is usually faster than global variables.
How can I pass a variable by reference in scheme?
An example of the functionality I want:
(define foo
(lambda (&x)
(set! x 5)))
(define y 2)
(foo y)
(display y) ;outputs: 5
Also, is there a way to return by reference?
See http://community.schemewiki.org/?scheme-faq-language question "Is there a way to emulate call-by-reference?".
In general I think that fights against scheme's functional nature so probably there is a better way to structure the program to make it more scheme-like.
Like Jari said, usually you want to avoid passing by reference in Scheme as it suggests that you're abusing side effects.
If you want to, though, you can enclose anything you want to pass by reference in a cons box.
(cons 5 (void))
will produce a box containing 5. If you pass this box to a procedure that changes the 5 to a 6, your original box will also contain a 6. Of course, you have to remember to cons and car when appropriate.
Chez Scheme (and possibly other implementations) has a procedure called box (and its companions box? and unbox) specifically for this boxing/unboxing nonsense: http://www.scheme.com/csug8/objects.html#./objects:s43
You can use a macro:
scheme#(guile-user)> (define-macro (foo var)`(set! ,var 5))
scheme#(guile-user)> (define y 2)
scheme#(guile-user)> (foo y)
scheme#(guile-user)> (display y)(newline)
5
lambda!
(define (foo getx setx)
(setx (+ (getx) 5)))
(define y 2)
(display y)(newline)
(foo
(lambda () y)
(lambda (val) (set! y val)))
(display y)(newline)
Jari is right it is somewhat unscheme-like to pass by reference, at least with variables. However the behavior you want is used, and often encouraged, all the time in a more scheme like way by using closures. Pages 181 and 182(google books) in the seasoned scheme do a better job then I can of explaining it.
Here is a reference that gives a macro that allows you to use a c like syntax to 'pass by reference.' Olegs site is a gold mine for interesting reads so make sure to book mark it if you have not already.
http://okmij.org/ftp/Scheme/pointer-as-closure.txt
You can affect an outer context from within a function defined in that outer context, which gives you the affect of pass by reference variables, i.e. functions with side effects.
(define (outer-function)
(define referenced-var 0)
(define (fun-affects-outer-context) (set! referenced-var 12) (void))
;...
(fun-affects-outer-context)
(display referenced-var)
)
(outer-function) ; displays 12
This solution limits the scope of the side effects.
Otherwise there is (define x (box 5)), (unbox x), etc. as mentioned in a subcomment by Eli, which is the same as the cons solution suggested by erjiang.
You probably have use too much of C, PHP or whatever.
In scheme you don't want to do stuff like pass-by-*.
Understand first what scope mean and how the different implementation behave (in particular try to figure out what is the difference between LISP and Scheme).
By essence a purely functional programming language do not have side effect. Consequently it mean that pass-by-ref is not a functional concept.