freenode/#lisp - IRC Chatlog
Search
6:53:52
makomo
i've looked at those and it's clear to me what they do i think, but i was still hoping for a larger explanation
6:54:10
makomo
usually the stuff that's in the glossary is defined somewhere in the standard explictily
6:54:59
makomo
i think i understand the concepts because it's not so different from C++'s storage duration for example
6:56:06
makomo
White_Flame: oh i remember that conversation from the other day but i wasn't following closely. where does it do that?
6:57:40
White_Flame
indefinite extent means that the language mechanics don't make a reference undefined
6:57:57
spiaggia
makomo: There is no mention of thread-local in the standard, simply because there is no mention of threads in the standard.
6:58:20
makomo
White_Flame: yup. i think of it as just because something that has been malloc'd but never free'd :-)
6:59:01
White_Flame
although the GC will eliminate non-referenced objects, which might fall in the same technical vocabulary
7:00:34
makomo
White_Flame: hm so, this implies thread-locality only if we assume the existence of threads and their usual behavior right?
7:01:07
White_Flame
"an extent whose duration is bounded by points of establishment and disestablishment within the execution of a particular form. "
7:05:33
makomo
White_Flame: iirc, the whole discussion was started because of the question whether every thread has its own dynamic environment and whether they share the global dynamic environment?
7:09:53
hajovonta
makomo: I haven't hold it yet, first my colleague will do it on the topic of Prolog, this Wednesday as planned
7:11:23
hajovonta
but Erlang and Prolog are also being teached on our universities, so Lisp is the most alien of all of them
7:12:20
hajovonta
makomo: I've heard there is a simple Prolog implementation, but I'm not sure if that is something useful or only a subset of some standardized Prolog because I'm not familiar with the language
7:12:39
hajovonta
makomo: also I don't have pointers (but Google will surely help me out with that :)
7:12:47
makomo
it's probably only just a subset. writing a serious prolog implementation would certainly take more than 50 lines.
7:15:52
White_Flame
the thread environments could be considered overlays onto the shared global environment
8:07:00
beach
The use of the situation :execute (or eval) controls whether evaluation occurs for other eval-when forms; that is, those that are not top level forms, or those in code processed by eval or compile. If the :execute situation is specified in such a form, then the body forms are processed as an implicit progn; otherwise, the eval-when form returns nil.
8:07:44
makomo
ah, my question wasn't formulated very well. i meant to ask does it interact with :compile-toplevel and :load-toplevel
8:09:41
makomo
and the fact that EVAL might perform implicit compilation doesn't mean anything right, i.e. it still only fires with :execute?
8:10:38
beach
makomo: Yes, if EVAL does implicit compilation, it must still respect the restrictions of EVAL in the standard.
8:10:47
makomo
if the answer is yes, is that due to the fact that EVAL doesn't consider the stuff it's evaluating a top-level form, or because it's just special cased by the standard somewhere
8:16:56
jackdaniel
word "only" gives it too little credit, most software is compiled in the end file-by-file, not from the repl. but you are right, top-level forms are important when you compile files
8:18:09
jackdaniel
(for instance you expect, that your defun will be visible to other functions in your file)
8:22:38
makomo
beach: well i wouldn't, but currently i'm exploring the details of how the file compiler and eval-when work. i'm not sure if one would even want the effects of the file compiler for "in-memory" stuff, but i don't see why not
8:23:05
makomo
i.e. why can't i take an arbitrary string and tell the file compiler to compile it, just like it would do after reading (in the "stream of text" sense) it
8:29:06
jackdaniel
makomo: that'd require VFS which is not part of CL standard (and not implemented in any implementation so far afaik)
8:29:19
jackdaniel
you may create a macro, which takes your string, writes it to temporary file and compiles it with compile-file
8:29:32
makomo
jackdaniel: that's one way to do it, but what about the standard defining something like COMPILE-STRING?
8:32:00
jackdaniel
makomo: I'd go with temporary files for now (there is no other way around that afaik). When vfs becomes *the thing* (probably never snh) then you will be able to create a virtual file from string
10:51:04
fm4d_
Hi, could someone explain this behaviour to me? https://pastebin.com/3ypJB8Cn I thought I understand closures in lisps and this really confuses me.
10:52:10
fm4d_
Why the 'var' variable behaves as if it is a part of closures surrounding the function.
10:53:40
beach
fm4d_: When you have constant data like that, the implementation is free to reuse the same constant each time you call the function, because, like I said, you are not allowed to modify it.
11:01:18
beach
And, technically, it is not a "closure", since it does not close over any lexical variables.
11:01:45
beach
The function TEST in the example is defined in the global environment, also known as the null lexical environment.
11:04:05
hajovonta
I know I asked this before, but.. I'm a bit confused over this null lexical environment thing. It is like when calling (eval) and then inside the eval I have null environment and can't access things outside that.
11:04:51
beach
If you mean things like (let ((x 10)) (eval 'x)), then yes, you are right, eval does not take into account the lexical variable x.
11:06:54
beach
If EVAL had to take into account the lexical environment, then you would have to keep X alive after the call to (f x).
11:08:04
beach
Furthermore, the compiler writer is allowed to replace the entire thing with (progn (f 10) (eval (read))) so that there is no longer any X.
11:09:03
beach
Again, if EVAL had to take lexical environments into account, then a host of optimizations would not be possible, and then you (perhaps not you personally, but many people here) would complain that Common Lisp is slow because it is impossible to optimize the code.
11:09:43
beach
hajovonta: The creators of Common Lisp were very smart that way. They pushed the envelope of the language as much as they could, but without making it hard for the compiler writer to optimize.
11:13:11
hajovonta
beach: compiler optimization is a good thing, but I have a (I think) special case when I would need to generate and evaluate forms at runtime, with access to the lexical environment. And I don't know yet how to do that.
11:14:12
beach
After all, SBCL with SLIME is able to evaluate forms relative to a lexical environment.
11:14:45
beach
You are still not protected from the compiler removing variables that are not lexically apparent.
11:17:20
TMA
another option would be to allow the capture of the lexical environment -- this could be used to provide the information to eval as well as to let the compiler know optimizations are not permissible in this particular part of the code; to make that portably is not well specified in the standard (there are macros with &env for capturing the environment, but the standard eval does not accept it)
11:17:26
beach
"Evaluates form in the current dynamic environment and the null lexical environment."
11:34:48
lukego
recommend a reasonably portable/stable/efficient library for doing asynchronous sockets/timers ("state machine style")? cl-async? iolib?
12:19:47
makomo
hajovonta: a thing that you could do is inject a let into the code that is being EVAL'd
12:20:29
makomo
so instead of (eval some-code) you would have (eval `(let (... bindings ...) ,@some-code))) :-D
12:22:08
hajovonta
the problem is essentially (let ((x 1)) (eval (read-from-string "(setf x 2)")) x)
12:24:17
makomo
but yeah, that x is then not visible to the environment that called EVAL in the first place
12:25:24
hajovonta
but, as you say, it works: (defparameter x 1) (eval (read-from-string "(setf x 2)"))
12:27:04
makomo
actually, it modifies one of the slots, and that slot is hash table that stores variables of the object language (the one i'm implementing)
12:27:25
makomo
so that effect is persistent because that hash table is floating somewhere in the lisp image
12:30:07
makomo
and the reason i want that in the first place is so that the code of the object language can just say "a" to acess the variable "a" of a component within the object language
12:30:24
makomo
rather than having to say something like "(gethash 'a (variables *current-object*))" or something
12:30:50
makomo
i.e. so it doesn't have to use any implementation details of the object language implementation
12:31:30
makomo
so i inject LETs like "(let ((a ...thing with *current-object*...)) ...actual code...)"
12:32:13
makomo
now that i think about it, this is for reading the variables only. for setting the variables i should probably use something like a symbol-macrolet
12:33:20
makomo
i don't know whether there's a "better" way or if we should even be bothered by this way
12:47:22
xificurC
I just got a question from colleagues what does "prog" stand for in progn or prog1, anyone knows?
12:50:14
makomo
perhaps the sequence of forms that you give to prog can be thought of as a "program", i.e. a sequence steps to execute in that particular order
12:51:52
xificurC
which is no different to normal code :) And program usually refers to something bigger, this is just a random block of code grouped together
12:55:37
Xach_
at ilc guy steele and someone else made a few jokes about the announcement of PROG back in the day. apparently it was pitched as making it possible to write programs in lisp.
13:02:52
nowhere_man
Has anyone written a macro that contains a defmacro? I'm really struggling here.
13:05:23
nowhere_man
Writing the "first-level" macro is very easy: (defmacro {lazy} ((&rest args) &body body) `(make-instance 'lazy-function :fun (lambda ,args ,@body)))
13:05:46
nowhere_man
Now I'd like to write several identical macros with the name and class changing
13:06:07
nowhere_man
shka: they are straight up mysterious, I've been playing with them for some time now
13:07:49
nowhere_man
and in this case, I would have liked to understand how I can manage to pass the class as a symbol
13:10:02
xificurC
(defmacro uber-lazy (mname class) `(defmacro ,mname (args &body body) `(make-instance ',,class :fun (lambda ,args ,@body))))
13:10:42
xificurC
(defmacro uber-lazy (mname class) `(defmacro ,,mname (args &body body) `(make-instance ',,class :fun (lambda ,args ,@body))))
13:13:47
nowhere_man
I'd like to be able to do both (make-function-maker {lazy} 'lazy-function) and (make-function-maker {other} (class-of something))
13:15:38
nowhere_man
It works like this with just class names: https://plaster.tymoon.eu/view/805#805
13:16:34
makomo
i was just about to ask, wouldn't that require for this defmacro to not be at the top-level
13:21:04
Bike
I mean, and you'll have to do (make-function-maker lazy 'lazy-function) instead of just (make-function-maker lazy lazy-function), of course.
14:26:59
makomo
the ",,@" in once-only still puzzles me, because i can't seem to get at the observer behavior using the formal definition
14:27:30
makomo
the rightmost ",@" splices in some list, and the leftmost "," then evaluates *every* element of the list
14:38:33
pjb
makomo: I beg to differ: (let ((l '((+ 1 2) (- 1 2) (* 3 4)))) ``(list ,,@l)) #| --> (list* 'list (list (+ 1 2) (- 1 2) (* 3 4))) |#
14:40:09
pjb
What matters, is that the inner , matches the inner `: (let ((out '((+ 1 2) (- 1 2) (* 3 4)))) `(let ((in '((/ 3 4) (/ 1 2)))) `(list ,@in ,,@out)))
14:40:15
pjb
(let ((out '((+ 1 2) (- 1 2) (* 3 4)))) `(let ((in '((/ 3 4) (/ 1 2)))) `(list ,@in ,,@out))) #| --> (let ((in '((/ 3 4) (/ 1 2)))) (list* 'list (append in (list (+ 1 2) (- 1 2) (* 3 4))))) |#
14:40:29
pjb
(eval (let ((out '((+ 1 2) (- 1 2) (* 3 4)))) `(let ((in '((/ 3 4) (/ 1 2)))) `(list ,@in ,,@out)))) #| --> (list (/ 3 4) (/ 1 2) 3 -1 12) |#
14:40:38
pjb
(eval (eval (let ((out '((+ 1 2) (- 1 2) (* 3 4)))) `(let ((in '((/ 3 4) (/ 1 2)))) `(list ,@in ,,@out))))) #| --> (3/4 1/2 3 -1 12) |#
14:41:34
pjb
You need eval, or a macro to evaluate the form: (eval (let ((l '((+ 1 2) (- 1 2) (* 3 4)))) ``(list ,,@l)) ) #| --> (list 3 -1 12) |#
14:41:53
pjb
and since we have two ``, we need two evals or two macros: (eval (eval (let ((l '((+ 1 2) (- 1 2) (* 3 4)))) ``(list ,,@l)) )) #| --> (3 -1 12) |#
14:45:42
makomo
pjb: isn't what i said true? your list is ((+ 1 2) (- 1 2) ...), and the result of evaluating the doubly nested backquote form twice is '(list 3 -1 12)
14:46:11
beach
jmercouris: The word is more commonly used to mean a dummy element that is part of the representation of a data structure, but that is not seen by the interface to that data structure.
14:46:59
beach
jmercouris: For instance, if you represent an empty queue by a single CONS cell, then you remove the special case to test whether the head and the tail pointers are both NIL.
14:47:58
jmercouris
I'm thinking about what the last thing you said, why would we test to see if the head and tail is both NIL? to test for empty queue?
14:48:55
jmercouris
so we can just check if the cons cell is pointing to nil instead of performing two checks
14:49:12
pjb
makomo: (let ((e '(+ 1 2))) `(list ,e)) #| --> (list (+ 1 2)) |# you see that the comma evaluates E, but doesn't evaluate the result of E.
14:49:25
beach
jmercouris: You typically check whether the head and the tail point to the same thing in order to determine whether the queue is empty.
14:49:42
pjb
And if you double the quotes and comma, even less: (let ((e '(+ 1 2))) ``(list ,,e)) #| --> (list* 'list (list (+ 1 2))) |#
14:50:27
pjb
makomo: again, you need something to evaluate the result of the backquote. Such as a compiler calling a macro and generating the code to evaluate the result of the macro, or an explicit call to eval.
14:50:29
makomo
pjb: is the thing on the right supposed to represent a "raw list" or the equivalent form that when evaluated gives the same thing?
14:50:51
pjb
makomo: don't confuse who does what. It's eval, or compile that will set things to evaluate the subexpression (+ 1 2).
14:53:28
makomo
the thing that's not clear to me, is how to get to that behavior, using the formal rules of backquote described in the spec
14:53:56
makomo
so evaluating a doubly nested backquote form with ,,@a in it first splices in the elements of a, and then evaluates all of those elements
15:19:03
pjb
makomo: in reality both commas "expand" or substitute the result of expression following the comma. The only question is where the binding are sought. And this is where the parenthetical aspect of backquote and comma matters.
15:20:44
makomo
the question where the bindings are sought is a simpler problem to me and is easy to understand by analogy either with parentheses as you say, or with "ladders" (the so-called ladder algorithm or whatever it was)
15:20:54
pjb
(let ((e '(+ 1 2)) (v (gensym))) `(let ((,v ,e)) `(list ,',v ,,v ,',e ,,e))) #| --> (let ((#1=#:g7204 #2=(+ 1 2))) (list* 'list (list* '#1# (list* #1# (list* '#2# (list #2#)))))) #| --> (list #:g7204 3 (+ 1 2) 3) |# |#
15:21:13
makomo
the confusing thing for me is what does the left "," do with the expansion of ",@" in ",,@"
15:22:10
pjb
Notice in (let ((e '(+ 1 2)) (v (gensym))) `(let ((,v ,e)) `(list ,',v ,,v ,',e ,,e))) how we HAVE to use TWO commas to get the V and the E bindings that are in the outer LET.
15:22:45
pjb
On the other hand, a single comma is needed in the `(let ((,v ,e)), because there's only one ` to traverse.
15:25:52
makomo
pjb: here's an example of ,,@ in the wild, https://github.com/keithj/alexandria/blob/master/macros.lisp#L61
15:26:17
makomo
what once-only does is not important right now, but i do know what it does and how it does it
15:29:19
pjb
makomo: more interesting a question, is why the lambda body uses ``(,,g ,,(cdr n)) instead of (list g (cdr n))
15:31:15
pjb
makomo: AFAICS, there's no difference between ``(,,g ,,(cdr n)) and (list g (cdr n)). It's the programmer loving ` and ,…
15:34:33
makomo
the result of mapcar is a list of the form '(`(,a1 ,b1) `(,a2, b2) ...) where ai and bi are the results of evaluating g and (cdr n) in the i-th iteration of mapcar
15:35:50
makomo
the elements of this list are spliced in front of a commad, meaning that all of these elements will be evaluated in the second evaluation
15:37:06
pjb
makomo: to see what a reader macro reads something as, you can just type the form at the REPL, prefixed by quote, so that it's not evaluated, but just read.
15:38:00
pjb
in ccl, '``(,,g ,,(cdr n)) --> (list* 'list* (list* g (list (list* 'list (list (cdr n))))))
15:38:28
pjb
(setf *print-pretty* nil) ; but the printer for ` may do its work even without *print-pretty*.
15:39:25
pjb
yes, so ``,,g is needed, because g contains an expression that when evaluated will return a variable name…
15:40:40
pjb
Well, you can say that it evaluate the following expression in the lexical context outside the second ` on the left.
15:42:30
makomo
the inner backquote will be evaluated in the lexical context set up by the outer let
15:54:43
beach
Let's say I am using an ideal debugger, and I am stopped at the beginning of the form (f (g a) (h b)). Can we agree that if I execute a STEP OVER, command, then (g a) will be evaluated, then (h b), then the call to f will be made and I will find myself stopped at the end of the initial form?
15:56:41
beach
Now, if I am again stopped at the beginning of the form (f (g a) (h b)) and I execute the STEP IN command, can we then agree that I will probably find myself stopped at the beginning of the form (g a)?
15:58:42
beach
My question is: Suppose I want the next stopping point to be the beginning of the first form of the function F, where would the current stopping point have to be located, and what is the name of the command that I need to execute?
16:01:33
beach
One possible answer would be: From the initial situation, I would issue a STEP IN command, followed by two step-over, which would take me to the end of the form (h b). I would then execute another STEP IN. Since there is no form to step into after (h b), I will instead step into the function F.
16:03:50
beach
Another one would be: From the initial situation, I would issue a STEP IN command, followed by two step-over, which would take me to the end of the form (h b). I would then execute a command that has yet to be defined, say STEP CALL, in order to step into the function F, whereas executing a STEP IN in that situation would step into the form following (f (g a) (h b)).
16:40:01
pjb
beach: about no form after (h b) I would note that I would often like to see the result of the stepped over form before continuing (or possibly retry the stepped over form, stepping in this time). Therefore I would insert automatically a stopping point just before the call to the function F.
16:41:38
pjb
similarly when you're stepping inside a function, we want a stop point once the result is elaborated and we're ready to return, but before we unwind the scopes of the function, so that we may jump back inside the function to retry something.
16:42:10
pjb
Yes, after evaluating each argument. The thing is that stopping points can be fusionned if there are no evaluations between them.
16:42:59
pjb
We stop before and after arguments, before and after the call, before and after the return, etc. A lot of stopping will be merged.
16:43:30
pjb
Perhaps things would be more obvious looking at the binding scopes, when they're established and unwound.
17:21:31
puchacz
hi, I have a web application in Lisp (hunchentoot etc.). I would like to add a backend server in Java, that would not be accessible in the external world, but my Lisp web application would talk to it. What shall I use please? jfli, lisplets, foil, abcl maybe....?
17:22:02
makomo
sjl: when the defmacro is expanded, i want it to expand into something that will define a macro with the name being the current value of the symbol i gave it
17:24:38
sjl
(defmacro define-macro-named (symbol &body body) `(defmacro ,(symbol-value symbol) ,@body)) would work if you don't care about lexical bindings
17:24:47
makomo
sjl: i'm only playing around with a question that was asked earlier today. https://plaster.tymoon.eu/view/806#806
17:30:35
pjb
You can have another intermediate macro. But the thing is that the name of the ultimate macro will have to be known at compilation time anyways, so it has to be evaluated in the macro-expansion environment (or in the compilation environment).
17:31:08
pjb
makomo: the point is to know who provides the expression. In general, it's the macro defining macro that computes the names…
17:31:51
pjb
(defmacro define-a-bunch-of-macros (parameters) `(progn ,@(mapcar (lambda (stuff) `(defmacro ,(compute-macro-name stuff) …)) …))
17:35:00
pjb
If not a macro, I call the functions generate-something. Those generate functions can be called from macros.
17:50:05
makomo
using a macro is correct, but i have to evaluate the arguments within the expander, not the expansion
18:00:51
makomo
but now i want to create generate-maker that takes an expression that evaluates to the name of the class
18:01:30
makomo
how can i evaluate the expression bound to "name" without having to call EVAL or the like
18:03:28
Bike
for example you'd have (generate-maker (class-of (make-instance 'some-class))) expand into (defmacro whatever (args &body body) (make-instance (class-of (make-instance 'some-class)) :fun (lambda ,args ,@body)))
18:05:47
makomo
so if macro-function didn't exist, i.e. if there was no way to define a macro other than defmacro (i know it doesn't make much sense do provide such an api, but let's speak hypothetically)
18:06:01
makomo
then there would be no other way other than using EVAL within the body of the macro (not the expansion)?
18:07:28
TMA
makomo: well, as defmacro is a macro itself it expands to something that does its shenanigans. that something would be necessarily implementation defined though
18:08:02
makomo
true. so there will always be a non-macro way to do it, the only issue being whether it is an implementation detail of the api or not
18:09:36
makomo
so if for example CL didn't provide macro-function and the ability to set the macro function, you'd have no portable way of defining macros at run-time, right?
18:10:14
beach
Simpler question about debugger interface: suppose you have a sequence of forms to evaluate, like the body of a PROGN or the argument forms of a function call. Would you prefer to go from the beginning of one expression to the beginning of the next one, or from the end of one expression to the end of the next one?
18:10:15
beach
I am asking because as far as the program counter is concerned, the end of one expression is probably the same address as the beginning of the next. My question is more where you would like to see the cursor each time.
18:10:19
pjb
makomo: if you know that macro functions are functions taking two arguments: a form, and an environment, then yes.
18:11:03
pjb
beach: well, you need to stop at the beginning, but then it's better to stop at the end of each form to report the results of each form.
18:12:02
makomo
pjb: i still don't see how your code solves anything though. you're not calling define-maker anywhere
18:12:57
pjb
beach: in a gui, you can display things in different places, you can insert lines, etc.
18:13:12
pjb
beach: it's customary to have an indicator (and for breakpoints too) at the beginning of the line.
18:13:51
pjb
So I think the best would be to insert space between the two form to display the indicator or display things.
18:14:27
makomo
Bike: so is it true that to achieve what i want i would either have to use EVAL within the macro's body or expand into something like (setf (macro-function ...) ...) as you said?
18:14:43
pjb
Eg. could use a phylactery containing the results of the previous form, and pointing between the two forms.
18:15:03
pjb
It would work as well if the two forms are on the same line (eg. arguments) or on different lines (progn).
18:15:27
beach
pjb: But what if one is the condition of an IF and the other is far away (the ELSE branch)?
18:16:22
TMA
beach: that being said, the form about to be evaluated is ill-specified itself -- is it the innermost form to be evaluated? or the outermost? [say the "next" form is (cons (cdr x) (car x)) ... I don't know in what case I would expect the cursor be: _(cons (cdr x) (car x)) and in which cases (cons (cdr _x) (car x)) ]
18:16:31
pjb
Furthermore, the user could want to keep around some phylactery, "pinning" them so the arrows would have to be elastic to let the user move the phylactery around to read what's below.
18:17:15
pjb
beach: perhaps you could have a look at Racket. IIRC they have a debugger that does something like this.
18:19:17
beach
TMA: I was talking about the STEP OVER command, which does not enter into sub-forms. In your example, the next form would be the one following (cons (cdr x) (car x)).
18:20:18
pjb
On one hand, inserting stuff may be bothering. On the other, displaying windows above the source too. In any case, if it's automatic, it's better than if it requires manual manipulation…
18:21:10
TMA
beach: ok. in step over mode it is definitely the opening parenthesis ... but what is a step over mode? isn't the step-over step-into decision postponed until after some feedback is given to the user?
18:21:30
beach
pjb: I don't consider inserting stuff in the kind of window I am talking about. The user would have to specify "edit" at which point some editor would be executed with the file in question.
18:21:50
pjb
beach: some debuggers also have a "finish" command, to continue execution until the end of the current function.
18:23:10
pjb
step in would stop before arguments, step into would stop at the entry of the function.
18:23:37
TMA
beach: yes, but in the 'usual' debuggers the selection is only done after the cursor is shown, so you cannot decide where to put it based on the choice the user has not yet made
18:24:08
MichaelRaskin
Hm, yes, a diifference between going through every subform in the source of the given fnuction, and falling through into the calls is a useful difference
18:24:34
TMA
beach: on the other hand, the usual debuggers are concerned only with lines, they do not usually have more precise/granular locations
18:25:06
beach
TMA: Yes, that's why I am asking. If I wanted to be line oriented, I would emulate something like GDB.
18:25:44
TMA
and so there is usually no simple way to step into H but not into F or G given (f (g) (h))
18:26:09
pjb
that said, perhaps we don't need to do anything special for the arguments: they're forms like others, so when we're stepping we'll stop in front of them like the others.
18:26:25
MichaelRaskin
TMA: if you are issuing each step command manually, you can just choose differently when H is evaluated
18:26:47
pjb
If we add the stop point at the end of each form to report result, we get automatically the stop before calling the function after evaluating all the arguments.
18:26:57
beach
TMA: SI would go to the beginning of (g), SO to the beginning of (h), SC would step into H.
18:27:29
pjb
From the debugger point of view, we could consider that all argument lists are wrapped in a call to list, so step out would be usable during argument evaluation, to stop before the call.