I am wondering about how I can do in Perl what I commonly do in lisp:
(defvar *verbose-level* 0)
(defun my-function (... &key ((:verbose-level *verbose-level*) *verbose-level*) ...) ...)
this means that my-function is run at the current level of verbosity, but I can pass it a different level which will affect all its calls too:
(defun f1 (&key ((:verbose-level *verbose-level*) *verbose-level*))
(format t "~S: ~S=~S~%" 'f1 '*verbose-level* *verbose-level*)
(f2 :verbose-level 1)
(format t "~S: ~S=~S~%" 'f1 '*verbose-level* *verbose-level*)
(f2 :verbose-level (1+ *verbose-level*))
(format t "~S: ~S=~S~%" 'f1 '*verbose-level* *verbose-level*))
(defun f2 (&key ((:verbose-level *verbose-level*) *verbose-level*))
(format t "~S: ~S=~S~%" 'f2 '*verbose-level* *verbose-level*))
[17]> (f1)
F1: *VERBOSE-LEVEL*=0
F2: *VERBOSE-LEVEL*=1
F1: *VERBOSE-LEVEL*=0
F2: *VERBOSE-LEVEL*=1
F1: *VERBOSE-LEVEL*=0
NIL
[18]> (f1 :verbose-level 4)
F1: *VERBOSE-LEVEL*=4
F2: *VERBOSE-LEVEL*=1
F1: *VERBOSE-LEVEL*=4
F2: *VERBOSE-LEVEL*=5
F1: *VERBOSE-LEVEL*=4
(note that the variable bindings are restored on exit - even abnormal - from functions).
How can I do something like that in Perl?
E.g., in misc.pm, I have our $verbose=0;.
How do I write a function which would bind $verbose to a value of its argument and restore its value on return?
Perl's concept of global variables is quite similar to special variables in CL.
You can “shadow” the value of a global variable with local:
our $var = 1;
func("before");
{
# a block creates a new scope
local $var = 2;
func("inside");
}
func("after");
sub func { say "#_: $var" }
Output:
before: 1
inside: 2
after: 1
If you local a value, the new value is visible throughout the whole dynamic scope, i.e. in all functions that are called. The old value is restored once the lexical scope is left by any means (errors, returns, etc). Tail calls do not extend the dynamic scope, but count as scope exit.
Note that global variables have a fully qualified name. From a different package, you would do something like
local $Other::Package::var = 3;
Other::Package::func("from a package far, far away");
This is commonly used to provide configuration for packages with a functional (non-OO) interface. Important examples are
Carp
and
Data::Dumper.
If I understand you correctly, you need to locally override a global variable inside a function.
package my_package;
our $verbose = 0;
sub function {
my ($arg1, $arg2) = #_; # getting function arguments.
local $verbose = $arg1;
}
It will restore old state of $verbose on return.
Related
I am trying to use a function (secondaryFunction or secondaryFunction2) passed in as a parameter to primaryFunction. However, when I run my code below:
(defun secondaryFunction (param1 param2)
NIL
)
(defun secondaryFunction2 (param1 param2))
NIL
)
(defun primaryFunction (transition param1 param2)
(transition param1 param2)
)
(primaryFunction 'secondaryFunction 0 0)
I get the following error:
*** - EVAL: undefined function TRANSITION
This seems strange, considering that I thought that I passed in secondaryFunction clearly as the transition parameter to primaryFunction?
There are separate function and value namespaces. In primary-function, you get the transition function as a value (actually the symbol here). Use funcall to call it:
(defun primary-function (transition param1 param2)
(funcall transition param1 param2))
Side Note: You are using a symbol, which means that funcall calls the function with that symbol as a name in the global environment. That's OK. You can also pass the function itself, with the function special operator (which has a shorthand #' reader macro):
(primary-function #'secondary-function 0 0)
Let's say I have a special var:
(defvar x 20)
then I do the following:
(let ((x 1)) (eval '(+ x 1))
which evaluates to 2.
According to CLHS, eval "Evaluates form in the current dynamic environment and the null lexical environment". So, I would expect to get 21 instead of 2.
Am I missing something?
Now if I have no dynamic binding for symbol y, evaluating
(let ((y 1)) (eval '(+ y 1))
I get condition: "The variable Y is unbound", which makes sense, since there is no dynamic binding for y.
Note: I'm using SBCL 1.0.57
Appreciate your help in advance!
in your example x is special which means it is bound in the dynamic environment
y is not special, so it is bound in the lexical environment
so at the time of the first eval the environments could be represented like this:
dynamic environment: { x : 1 } -> { x : 20, ...other global variables... } -> nil
lexical environment: nil
the symbol x is special so eval looks up x in the current dynamic
environment and finds x = 1
assuming it was run in same lisp as the last example, the environment of your second eval looks like this:
dynamic environment: { x : 20, ...other global variables... } -> nil
lexical environment: { y : 1 } -> nil
the symbol y is not special so eval looks up y in the null
lexical environment -- not the current lexical environment -- and finds nothing.
this makes sense when you realize that lisp is usually compiled, and the lexical
environment can be optimized down to simple mov instructions in some cases.
DEFVAR declares its variables special. Globally, everywhere. You can also not remove this easily.
That's also the reason you should never use common names like x, i, list as variable names for DEFVAR. Make sure that you use *x*, *i* and *list* instead. Otherwise all variables, even local ones, with these common names are declared special.
Here are two simple functions that use push on a variable passed in:
(defun push-rest (var) (push 99 (rest var)))
and
(defun just-push (something) (push 5 something))
The first one will permanently mutate the var passed. The second does not. This is quite confusing for someone who is learning the scoping behavior of this language:
CL-USER> (defparameter something (list 1 2))
SOMETHING
CL-USER> something
(1 2)
CL-USER> (just-push something)
(5 1 2)
CL-USER> something
(1 2)
CL-USER> (push-rest something)
(99 2)
CL-USER> something
(1 99 2)
In push-rest why isn't the var's scope local to the function like in just-push, when they are both using the same function, push?
According to Peter Siebel's Practical Common Lisp, Chapter 6. Variables: This might help you a lot:
As with all Common Lisp variables, function parameters hold object references. Thus, you can assign a new value to a function parameter within the body of the function, and it will not affect the bindings created for another call to the same function. But if the object passed to a function is mutable and you change it in the function, the changes will be visible to the caller since both the caller and the callee will be referencing the same object.
And a footnote:
In compiler-writer terms Common Lisp functions are "pass-by-value." However, the values that are passed are references to objects.
(Pass by value also essentially means copy; but we aren't copying the object; we are copying the reference/pointer to the object.)
As I noted in another comment:
Lisp doesn't pass objects. Lisp passes copies of object references to functions. Or you could think of them as pointers. setf assigns a new pointer created by the function to something else. The previous pointer/binding is not touched. But if the function instead operates on this pointer, rather than setting it, then it operates on the original object the pointer points too. if you are a C++ guy, this might make much more sense for you.
You can't push on a variable passed. Lisp does not pass variables.
Lisp passes objects.
You need to understand evaluation.
(just-push something)
Lisp sees that just-push is a function.
Now it evaluates something. The value of something is a list (1 2).
Then it calls just-push with the single argument (1 2).
just-push will never see the variable, it does not care. All it gets are objects.
(defun push-rest (some-list) (push 99 (rest some-list)))
Above pushes 99 onto the rest, a cons, of the list passed. Since that cons is visible outside, the change is visible outside.
(defun just-push (something) (push 5 something))
Above pushes 5 to the list pointed to by something. Since something is not visible outside and no other change has made, that change is not visible outside.
push works differently when it's passed a symbol or list as it's second argument. Pehaps you might understand it better if you do macroexpand on the two different.
(macroexpand '(push 99 (rest var)))
;;==>
(let* ((#:g5374 99))
(let* ((#:temp-5373 var))
(let* ((#:g5375 (rest #:temp-5373)))
(system::%rplacd #:temp-5373 (cons #:g5374 #:g5375)))))
Now most of this is to not evaluate the arguments more than once so we can in this case rewrite it to:
(rplacd var (cons 99 (rest var)))
Now this mutates the cdr of var such that every binding to the same value or lists that has the same object in it's structure gets altered. Now lets try the other one:
(macroexpand '(push 5 something))
; ==>
(setq something (cons 5 something))
Here is creates a new list starting with 5 and alters the local functions binding something to that value, that in the beginning pointed to the original structure. If you have the original structure in a variable lst it won't get changed since it's a completely different binding than something. You can fix your problem with a macro:
(defmacro just-push (lst)
(if (symbolp lst)
`(push 5 ,lst)
(error "macro-argument-not-symbol")))
This only accepts variables as argument and mutates it to a new list having 5 as it's first element and the original list as it's tail. (just-push x) is just an abbreviation for (push 5 x).
Just to be clear. In an Algol dialect the equivalent code would be something like:
public class Node
{
private int value;
private Node next;
public Node(int value, Node next)
{
this.value = value;
this.next = next;
}
public static void pushRest(Node var)
{
Node n = new Node(99, var.next); // a new node with 99 and chained with the rest of var
var.next = n; // argument gets mutated to have new node as next
}
public static void justPush(Node var)
{
var = new Node(5, var); // overwrite var
System.out.print("var in justPush is: ");
var.print();
}
public void print()
{
System.out.print(String.valueOf(value) + " ");
if ( next == null )
System.out.println();
else
next.print();
}
public static void main (String[] args)
{
Node n = new Node( 10, new Node(20, null));
n.print(); // displays "10 20"
pushRest(n); // mutates list
n.print(); // displays "10 99 20"
justPush(n); // displays "var in justPush is :5 10 99 20"
n.print(); // displays "10 99 20"
}
}
(push item place)
It work as follows when the form is used to instruct the place where this is referred to in the setf:
(setf place (cons item place))
Basedon your profile, it looks like you have familiarity with C-like languages. push is a macro, and is the following equivalence is roughly true (except for the fact that this would cause x to be evaluated twice, whereas push won't):
(push x y) === (setf x (list* x y))
That's almost a C macro. Consider a similar incf macro (CL actually defines an incf, but that's not important now):
(incf x) === (setf x (+ 1 x))
In C, if you do something like
void bar( int *xs ) {
xs[0] = xs[0] + 1; /* INCF( xs[0] ) */
}
void foo( int x ) {
x = x + 1; /* INCF( x ) */
}
and have calls like
bar(zs); /* where zs[0] is 10 */
printf( "%d", zs[0] ); /* 11, not 10 */
foo(z); /* where z is 10 */
printf( "%d", z ); /* 10, not 11 */
The same thing is happening in the Lisp code. In your first code example, you're modifying contents of some structure. In your second code example, you're modifying the value of lexical variable. The first you'll see across function calls, because the structure is preserved across function calls. The second you won't see, because the lexical variable only has lexical scope.
Sometimes I wonder if Lisp aficionados (myself included) promote the idea that Lisp is different so much that we confuse people into thinking that nothing's the same.
The macro, transform!, as defined below seems to work for => (transform! ["foo" 1 2 3]). The purpose is to take in a list, with the first element being a string that represents a function in the namespace. Then wrapping everything into swap!.
The problem is that transform! doesn't work for => (transform! coll), where (def coll ["foo" 1 2 3]). I am getting this mystery exception:
#<UnsupportedOperationException java.lang.UnsupportedOperationException: nth not supported on this type: Symbol>
The function:
(defmacro transform!
" Takes string input and update data with corresponding command function.
"
[[f & args]] ;; note double brackets
`(swap! *image* ~(ns-resolve *ns* (symbol f)) ~#args))
I find it strange that it works for one case and not the other.
Macros work at compile-time and operate on code, not on runtime data. In the case of (transform! coll), the macro is being passed a single, unevaluated argument: the symbol coll.
You don't actually need a macro; a regular function will suffice:
(defn transform! [[f & args]]
(apply swap! *image* (resolve (symbol f)) args)))
Resolving vars at runtime could be considered a code smell, so think about whether you really need to do it.
You're passing a symbol to the macro, namely coll. It will try to pull that symbol apart according to the destructuring statement [f & args], which won't be possible of course.
You can also use (resolve symbol) instead of (ns-resolve *ns* symbol).
A list in lisp is a series of cons cells, but in Tcl, a list is a string with whitespace separating the elements. For translating code from lisp to tcl, one might simply take lisp lists and translate them to Tcl lists. However, this runs into trouble with side effecting cons cells not coming across to the Tcl code. For example, consider this code in lisp:
(setq a (list 1 2 3 4))
(let ((b a)
(a (cddr a)))
(declare (special a b))
(setf (cadr b) ‘b)
(setf (cadr a) ‘d)
(print a))
(print a)
;; Results in:
(3 d)
(1 b 3 d)
Is there a Tcl package that would provide a better emulation of lisp lists in Tcl? Does such package offer easy conversion to regular Tcl lists?
What might the above code look like in Tcl using such package?
Lisp cons cells can't be directly modeled as Tcl values because of fundamentally different semantic models. Lisp uses a model whereby values are directly updatable; the value is the memory cell. Tcl uses a different model with values which are conceptually immutable and where there is no difference in principle between any “1 2 3 4” that happens to be lying around from any other; mutable entities in Tcl are variables with names (the name strings themselves are immutable, of course…) This immutability makes sense at the level of simple values, but it extends also to Tcl's lists and dictionaries; mutation operations all either return a new value or update a variable. (The implementation is more efficient than this, using a copy-on-write strategy to preserve the semantic model of immutability while being able to implement things with mutation of the value itself when that is actually known to be semantically equivalent.)
Because of this, you have to construct updatable cons cells as variables. Here's how you might do it:
proc cons {a b} {
global gensym cons
set handle G[incr gensym]
set cons($handle) [list $a $b]
return $handle
}
proc car {handle} {
global cons
return [lindex $cons($handle) 0]
}
proc cdr {handle} {
global cons
return [lindex $cons($handle) 1]
}
proc setCar {handle value} {
global cons
lset cons($handle) 0 $value
}
# Convenience procedures
proc makeFromList args {
set result "!nil"
foreach value [lreverse $args] {
set result [cons $value $result]
}
return $result
}
proc getAsList {handle} {
set result {}
while {$handle ne "!nil"} {
lappend result [car $handle]
set handle [cdr $handle]
}
return $result
}
set a [makeFromList 1 2 3 4]
# Use some local context; Tcl doesn't have anything exactly like Lisp's "let"
apply {a {
set b $a
set a [cdr [cdr $a]]
setCar [cdr $b] "b"
setCar [cdr $a] "d"
puts [getAsList $a]
}} $a
puts [getAsList $a]
This produces the expected output (given that Lisp and Tcl have different ideas how a list should be formatted).