freenode/#lisp - IRC Chatlog
Search
15:29:41
Ukari
would it be a good idea to make lamdba and defvar check their parameter's name to enforce name style?
15:36:08
buffergn0me
That would be really annoying. Especially when porting code from other languages
15:43:28
beach
Ukari: Lambda is perfectly able to use special variables as parameters. What that means is that the special variable gets bound upon entry to the function and unbound upon exit. For example ((lambda (*print-base*) (print 234)) 2)
15:44:52
beach
buffergn0me: It would be especially annoying because a conventionally named special variable could then not be used in a lambda expression.
15:46:23
Bike
It's not a bug. x is a special variable, and once the outer function has returned its binding of x is extinguished, so the inner function uses the global value.
15:48:36
phoe
in SBCL at least, (let ((*foo* 42)) ...) will emit a warning if *foo* is not declared special
15:49:37
beach
phoe: I think Ukari is suggesting that LAMBDA check that there are no earmuffs in the parameters.
15:51:14
phoe
; caught STYLE-WARNING: using the lexical binding of the symbol (COMMON-LISP-USER::*FOO*), not the dynamic binding, even though the name follows the usual naming convention (names like *FOO*) for special variables
15:55:04
Ukari
in (lambda (x) (lambda () (print x))) or (let ((x 5)) (lambda () (print x))), when you funcall the outside lambda or get the let result, it returns you a FUNCTION
15:55:47
phoe
except X is special, so its value is taken from the dynamic environment and not the lexical one.
15:56:46
Ukari
In a CLOSURE, a free variable in bind to its lexcial context, so use (defvar) won't change it.
15:57:09
phoe
it returns a function in my case, and it won't matter anyway if a FUNCTION or a CLOSURE is returned
16:00:05
phoe
TEST still works as it did, the variable used inside it was lexical and does not suddenly become dynamic because of a later DEFVAR.
16:04:27
pierpal
Life must be very exciting for people learning programming languages by experiments
16:08:35
Ukari
why (funcall (lambda () (lambda () (print "foo")))) returns a FUNCTION, it seems should return a CLOSURE
16:08:48
makomo
i think you accidentally had X proclaimed special when you were evaluating that lambda
16:15:34
Ukari
my mistake, what (funcall (lambda (x) (lambda () (print x)))) returns might be a CLOSURE or FUNCTION, it determines by the context
16:16:41
makomo
so yes, it depends on the state of the lisp image, i.e. the specialness of the symbols involved
16:17:03
phoe
depending on whether your symbols are proclaimed special, your variables may be lexical or dynamic
16:32:51
phoe
I don't have the time or patience to register at https://sourceforge.net/p/clisp/bugs/ now
16:44:41
Ukari
makomo, when (funcall *builder* 10) runs, the (funcall *builder* 10)'s result might be a CLOSURE or a FUNCTION, that determined by the context. Since you use (defvar x), x was treated as a global dynamic scope variable so (funcall *builder* 10) returns FUNCTION
17:15:37
makomo
LOAD-ing this lisp file gives 10 10 200, but compiling it and then loading the FASL gives an error: "X is unbound"
17:16:33
jackdaniel
dlowe: you mean in documentation? how is this relevant to green threads? you may implement serve-event without gt (but I wouldn't be suprised if cmucl has them anyway)
17:19:09
jackdaniel
makomo: when you load a file, it is processed sequentially, toplevel form after toplevel form
17:20:06
jackdaniel
but don't think too much about how it (eval-when) works in detail unless you have some time and want a good puzzle
17:47:55
makomo
jackdaniel: i think i understand how EVAL-WHEN works because i've studied it a couple of times
17:48:06
makomo
jackdaniel: what i don't understand is what exactly is different between these two examples
17:50:29
makomo
hmm, does this have to do with the fact that the different stages of processing can be interleaved?
17:57:59
gendl
Hi, is anyone experienced with cl-json? I'm trying to encode a nested plist: (json:encode-json-plist (list :xaxis (list :visible nil)))
17:59:02
gendl
so it looks like it only converts the outer plist into a JSON plist-type thingie. The inner one just becomes a JSON sequence or whatever TF they call it
18:00:06
gendl
I have a feeling I have to call json:encode-json-plist recursively somehow on the inner plists, but I'm not sure how I would make the result come out properly nested..
18:00:55
Bike
and encode-json is documented to make an array for a list, unless you do the explicit encoder
18:02:09
gendl
Oh yes, I see some hints about the explicit encoder here: https://www.cs.northwestern.edu/academics/courses/325/readings/web-tips.php
18:13:09
gendl
Indeed - the docs for method encode-json talk about the guessing-encoder and explicit-encoder. And it looks like using :object as (car S) is the same as using :plist. Anyway thanks for the pointers, this will let me do what I need.
19:00:47
makomo
Bike: am i not supposed to COMPILE-FILE some file and then load it later on within a fresh image?
19:37:39
akkad
ACTION put all the slack/confluence/jira/github interface commands into a CL cli. no longer have to use a browser.</lispy>
19:56:10
makomo
phoe: to conclude the whole discussion from today, the "error" with http://rextester.com/CQFO22548 was to assume that *builder* will refer to a compiled-function, right?
19:57:02
makomo
adding a (compile nil (lambda ...)) does fix the "issue", i.e. the difference in results when the file is loaded vs. when it's compiled and then loaded (using clisp of course, sbcl gives the same results in both cases)
20:09:49
Bike
by other stuff i meant like, keeping an inline definition around, informing the compiler to avoid warnings, blabla
20:10:17
cgay
I'm finding that slime-edit-definition doesn't always work when I already have the target file open in my buffer. i.e., it works the first time, when it has to open the file, but then later if I M-. the same symbol it jumps to the wrong place in the buffer.
20:16:50
knobo
cgay: I think you have to recompile the whole file if you edit parts of it (adding or removing lines).
20:20:14
makomo
phoe: i still don't understand why the value returned by *lambda1* is changed after defvar-ing x though
20:21:00
makomo
phoe: it makes sense that, since *builder* is an interpreted function, it might inspect x every time to check whether it's special or not and either return a closure or a function
20:21:31
Bike
oh, well, yes. the interpreter presumably looks up whether the symbol is special at runtime.
20:21:58
makomo
Bike: this is the original example, not the one i linked to you (when i forgot to recompile the file)
20:22:43
makomo
it makes sense that the result of *builder* might be different depending on the specialness of x
20:23:33
makomo
dlowe: when learning something, one of the worst things you can do is say "meh whatever" and drop it, imo
20:24:02
dlowe
makomo: sometimes the experts will say "you're wasting your time on this trivial detail," and sometimes they're right.
20:24:29
dlowe
makomo: the code is open source and no one here knows the answers to the exacting detail you require
20:25:00
dlowe
so I think your best bet (without any irony) is to actually dive into the compiler code for each to see why there's a difference
20:25:51
Bike
evaluating a (lambda ...) might literally consist of just copying the body into an interpreted function object, and not examining it in any way.
20:25:58
makomo
i guess it makes sense, but i thought that since in the first case a closure is returned, that it would just be "hardcoded" within the function
20:26:11
makomo
but i guess a better model would be that it would evaluate X in its captured lexical environment
20:27:55
Bike
it is sort of an ambiguous case though. i can imagine interpreters that would treat it like a lexical binding.
20:28:46
makomo
mhm. so in the end it's implementation defined? and with compiled functions it is guaranteed that X will be considered either a lexical or a dynamic binding, depending on the specialness of the symbol X, as per the clause you linked, right?
20:31:21
White_Flame
SBCL does at least give warnings when you redefine some assumption that it baked in previously
20:36:21
White_Flame
the compiler does not appear to be mandated to bake in compile-time knowledge of specialness
20:37:48
White_Flame
ah, but in 3.2.2.3: "Special proclamations for dynamic variables must be made in the compilation environment. Any binding for which there is no special declaration or proclamation in the compilation environment is treated by the compiler as a lexical binding."
20:44:19
makomo
does (compile nil (lambda (x) (lambda () x))) ensure that the functions returned by the inner lambda will be compiled too?
20:49:23
makomo
"The consequences are undefined if the lexical environment surrounding the function to be compiled contains any bindings other than those for macros, symbol macros, or declarations."
21:52:11
knobo
Would a function created by def be garbage collected (defmacro def () (let ((n (gensym))) `(defun ,n () (format nil "t"))))
21:53:55
phoe
so it will stay around, even if you have no real means of accessing that function after it's defined.
21:58:16
phoe
Like, if a symbol is no longer accessible, then all functions and variables named after that symbol may be collected.
21:58:47
phoe
But I have no idea if such a thing happens. You could try checking it out yourself by defining a finalizer on the created function object and see if it ever gets triggered.
0:34:41
Bike
the reason it happens is that docstrings are associated with underlying functions rather than closures, of course.
0:41:16
pillton
I am not sure I understand the difference between your example and https://plaster.tymoon.eu/view/824#824.
0:43:49
Bike
In my example the two functions almost certainly have the same underlying, eh, code object.
0:49:22
ealfonso
perhaps not a good idea, but in defstruct is it possible to spcify a default init form that uses a previously defined slot? is there a way to access "this"?
0:50:00
Bike
there isn't, but you could define a constructor that uses another parameter as a default
0:50:20
aeth
Whenever I do anything fancy with struct initialization, I tell it to make the constructor a %make-foo and I write my own make-foo constructor using %make-foo
0:51:34
devon
(format nil "~,6F" 3738064606071093/1000000) => "3738064600.000000" ; I'd prefer "3738064606.071093"
0:54:27
aeth
#'float is a bit awkward. It defaults to your default float format (in your case, and in most cases, that's single-float), but if you want to use another float format you have to provide some number of that format, in this case 1d0 (the "d0" instead of "e0" forces it to be a double)
0:57:09
aeth
Actually, apparently the default is always single-float. The difference between #'float and #'coerce is that #'float won't coerce something that is already a float.
0:59:39
Bike
you might want to consider laying out the decimal yourself. it's kind of a pain, but it beats weird rounding unintuitiveness.
1:00:34
Bike
like (multiple-value-call #'format nil "~d.~d" (floor 3738064606071093 1000000)) i mean.
1:02:59
aeth
If you do something like this you should probably write a unit test that compares it to the float version. They could differ, but if the decimal part differs by an order of magnitude or more, that's probably the leading 0s bug popping up or something similar
1:03:18
devon
Thanks, (format nil "~,6F" (coerce 3738064606000000/1000000 'double-float)) sure beats (let* ((n 3738064606071093/1000000) (s 1000000) (sn (* s n))) (multiple-value-bind (q r) (floor sn s) (format nil "~D.~6,'0D" q r)))
1:04:45
aeth
yeah, most of the time you use multiple-value-bind, you probably actually want multiple-value-call
1:15:03
pillton
Bike: Well, I think that documentation sharing thing is wrong. Imagine the surprises someone would have when using the programmatic interface to construct an environment. Secondly, an implementation may consider "compressing" code in fasls by sharing code objects.
1:20:24
devon
THX² Bike, aeth: (let ((n 3738064606071093/1000000)) (string= (format nil "~,6F" (coerce n 'double-float)) (let ((s 1000000)) (multiple-value-call #'format nil "~D.~6,'0D" (floor (* s n) s))))) => T
1:22:53
Bike
if you have a fraction already just do (format nil "~d~6,'0d" (numerator n) (denominator n))
1:25:33
aeth
devon: you wouldn't want string=, though, you'd want to find where the . is and then parse-integer and then divide the larger one by 10 until they're of the same base-10 length (but not quite beacuse you also have to take into account leading 0s) and then compare them.
1:27:30
aeth
Bike's version will prefix 0 for leading 0's to get it up to 6, but if the part after the decimal point is longer than 6, it will display them all. Afaik, the double float version will always cut it off after 6 decimal places after the decimal point. So the lengths could differ.
1:42:38
devon
Printing present-day universal times to µs, DOUBLE-FLOAT-EPSILON seems perilously close to dropping a low order bit. Perhaps it's time to define ~:F
1:52:33
devon
(format nil "~,,-6F, ~:*~,6,-6F" 1) => "1.0, 0.000001" ; is this a bug in CCL or a bug in the spec?
2:07:36
aeth
destructuring bind is most useful in macros. In fact, the lambda list of macros kind of builds it in to save a few levels of destructuring-binds.
2:08:36
aeth
a macro's lambda list might be (name (x y) &body body) and that's equivalent to it being (name parameters &body body) with a destructuring-bind in the macro of (destructuring-bind (x y) parameters ...)
2:11:20
aeth
So you're ensuring that a list matches some pattern, and binding the elements to that pattern. in (destructuring-bind (x y) (list 1 2) ...) x will be 1 and y will be 2. And (list) will be an error and (list 1 2 3) will be an error
2:12:43
aeth
The structure in destructuring-bind can be complicated like (x (y &optional z) (u (v &rest w)) &key a b c)
2:13:37
aeth
With multiple-value-bind you're just dealing with a bunch of values. so (multiple-value-bind (a b c) (values 1 2 3) (+ a b c)) => 6