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.