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).
Related
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.
guys,
look at the code first:
(defmacro map-remove- [v w]
`(dosync
(ref-set ~v (dissoc #~v (keyword ~w)))))
(defmacro set-remove- [v w]
`(dosync
(ref-set ~v (disj #~v ~w))))
(defmacro clean- [v]
`(dosync
(ref-set ~v (empty #~v))))
They work fine now , but I want write a more general macro to combine "map-remove-" and "set-remove-" in one. according my C/Java experience I chose "case" but obviously the case can't use in macro defination cause "The test-constants are not evaluated. They must be compile-time literals", the following code won't work:
(defmacro [x]
(case (type x) ;;;;;;;;;;; This will never work!directly reach to default clause
....))
anybody has any suggestion? very appreciate.
You can use the functions map? and set? to test whether a value is a map or a set respectively.
I'm not sure I have enough perspective on what you're trying to do here though - I've substituted a macro instead of a function, because I can't see the necessity for a macro in the sample you've given.
;; Create a function to remove in a different way when given a map/set and a string
(defn remove- [v w]
(dosync
(cond
(map? #v)
(ref-set v (dissoc #v (keyword w)))
(set? #v)
(ref-set v (disj #v w)))))
;; Set up some mutable refs
(def m (ref {:a 1 :b 2}))
(def s (ref #{"a" "b" "c"}))
;; Remove from the refs
(remove- m "b") => {:a 1}
(remove- s "b") => #{"a" "c"}
On a side note - are you sure you need to use refs? I know that coming from a C/Java background, mutability is the default, but I've never actually had to use it in Clojure so far. Clojure places a lot of emphasis on immutability, and most things can be done (often very elegantly) just by using functions on immutable values.
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.
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).
I'm writing a scheme interpreter, and in the case of an if statement such as:
(if (< 1 0) 'true)
Any interpreter I've tried just returns a new prompt. But when I coded this, I had an if for whether there was an alternative expression. What can I return in the if such that nothing gets printed?
(if (has-alternative if-expr)
(eval (alternative if-expr))
#f) ;; what do I return here?
According to the R6RS specification:
If <test> yields #f and no <alternate>
is specified, then the result of the
expression is unspecified.
So go wild, return anything you want! Although #f or '() are what I, personally, would expect.
Scheme can indeed return no values:
> (values)
In R5RS the one-armed form of if is specified to return an unspecified value.
That means it is up to you, to decide which value to return.
Quite a few Schemes have chosen to introduce a specific value called
"the unspecified value" and returns that value.
Others return "the invisible value" #<void> and the REPL is written
such that it doesn't print it.
> (void)
At first one might think, this is the same as (values),
but note the difference:
> (length (list (void)))
1
> (length (list (values)))
error> context expected 1 value, received 0 values
(Here (list ...) expected 1 value, but received nothing)
If #<void> is part of a list, it is printed:
> (list (void))
(#<void>)
A number of Schemes (PLT, Ikarus, Chicken) have a void type, which you can produce with (void).
In PLT at least, void is what you get when you do (when (< 1 0) #t).
(PLT v4 doesn't allow if without an else clause.)
When the return value is unspecified you can return what you like; the user just can't rely on that value being there, ever, or across implementations.
First, it's OK to require if to have an else clause, if it makes it easier for you. Second, Scheme supports returning multiple values from a function, so if you were to implement the return values as a list, you could have an empty list signify that no return value was given.
(if (has-alternative if-expr)
(eval (alternative if-expr)) ; make sure eval returns a list
'())
An important distinction here: I'm not returning an empty list if there was no else clause. The empty list signifies that there was no return value. If there were one return value from an expression (say it was 3) you would have (3) as the return from the eval behind the scenes. Similarly, returning multiple values from an expression would cause the eval return list to have multiple elements.
Finally, in all practicality, you could really return anything if the condition fails and there's no else, because it would be an error in a program to attempt to capture the value of a function that doesn't return anything. As such, it would be the job of the programmer, not the language, to catch this error.
Weird people would return 'nil or '|| (the empty symbol). The problem is to return a symbol that cannot be return by (eval (alternative if-expr)) to avoid confusion.
If anything can be returned by (eval (alternative if-expr)) and you still want to know whether you came in this alternative or not, you have to pack the result with more information :
(if (has-alternative if-expr)
(cons #t (eval (alternative if-expr)))
(cons #f #f))
Thus, the result is a cons cell. If its car is #t, then you evaled something. If it is #f, you didn't.
What is wrong with just:
(if (has-alternative if-expr) (eval (alternative if-expr)))
?