freenode/#lisp - IRC Chatlog
Search
18:35:46
pjb
eta: notably, macros are expanded at compilation time, while lexical bindings are established at run-time. Like, in a 100 years, on a different computer (probably an emulator then).
18:36:03
eta
pjb, I want to write (let ((a 1)) (macrolet ((do-thing-with-a (b) `(+ ,a ,b))) (do-thing-with-a 2)))
18:36:57
pjb
eta: if you want to have variables that you can mutate in the macro (at macroexpansion time/compilation time) and then access it (or not) at run-time, you will need to write your own MACRO-LET macro.
18:37:55
pjb
(symbol-macrolet ((a 1)) (macrolet ((do-thing-with-a (b) `(+ ,a ,b))) (do-thing-with-a 2))) #| --> 3 |# seems conforming to me.
18:38:26
pjb
eta: if you changed ,a to a it would indeed work with let, since a would be referenced a run-time then.
18:39:03
eta
pjb, I hadn't seen that SYMBOL-MACROLET trick before (nice!), but I'll just go with a instead of ,a for this case :)
18:40:31
pjb
eta: just keep in mind of WHEN different expressions are evaluated. (macroexpansion time, compilation time, load time, run-time, when evaluated by a call to EVAL, when read (reader macros, #.) etc).
18:49:52
jcowan
My sense is that a construct for defining recursive local macros is not sufficiently useful.
18:50:40
jcowan
Indeed, I think it may be unnecessary, given that the result of a macro procedure is itself expanded again.
18:51:18
jcowan
So it would only come up if you want macro A and B, declared in the same scope, to invoke one another in their bodies
0:07:41
jcowan
Bike: In the R6RS standard it is possible to use macros before they are defined, except at the REPL (whose behavior R6RS does not specify). I argued against this (mis)feature in R7RS using a parable, "The Tale of Professor Simpleton and Dr. Hardcase" <https://www.mail-archive.com/r6rs-discuss@lists.r6rs.org/msg04199.html>
0:24:35
_death
if macro forms are expanded just before they are evaluated, then it is possible to have them stored before macro definition (but not in CL)
0:35:16
jcowan
(aeth: it's only possible within a library, the assumption being that you read in the whole library and process the syntax definitions before any variable definitions.)
0:37:21
LdBeth
is there any optimizations for a quite large array with only small integers as elements?
0:40:16
no-defun-allowed
Odds are the upgraded element type of (integer 1 12) would be (unsigned-byte 8)
0:41:28
no-defun-allowed
(Right, a number is an inclusive integer designator unless I wrap it in a list)
0:42:02
no-defun-allowed
In CCL: (upgraded-array-element-type '(integer 1 12)) ; ⇒ (UNSIGNED-BYTE 8)
0:46:16
no-defun-allowed
I...don't think many processors have instructions for manipulating 4-bit quantities, so it would probably only be better at saving memory.
1:34:14
pjb
LdBeth: most implementations also have octet vectors. You can also assume fixnum vectors.
1:43:53
jcowan
there's a case to be made that 1 bit per byte is more performant if you can afford the space
1:47:50
pjb
It really depends on the operation. CL has a set of bit-* operations that work on whole bit-vectors. For those operations, packing bits in words is more efficient, both in space and time.
1:54:45
jcowan
But it's not true that aref is the only slow operation: for example "rotate (CL) byte" is not efficient at all with 1 bit per bit
1:58:48
pjb
Again, (rotatef (aref bv 0) (aref bv 1) (aref bv 2) (aref bv 3) (aref bv 4) (aref bv 5) (aref bv 6) (aref bv 7)) can be very efficient in CL (one read, one rotation of the octet, one store).
2:01:36
jcowan
Those are the simple cases. Try using the constants 2, 3, 5, 7, 11, 13, 17, 19 instead
2:13:11
aeth
The inability to declare something pure (beyond inlining and hoping) is probably one of the biggest weaknesses of CL optimizations. That is, you can have something effectively constant that's not seen as constant, unless you go out of your way to e.g. run it with #.
2:14:59
aeth
A pure FP subset of CL that compiles to CL should be able to beat idiomatic CL in performance in some cases.
2:17:04
aeth
A related weakness is that you can have something literal like '(1 2 3 4) and you can see (e.g. with disassemble) the compiler have fun optimizing it within a function, but that's as far as it can go.
2:17:40
aeth
(defun foo () (let ((l '(1 2 3 4))) (car l))) ; disassemble this in SBCL and you can see that it returns 2, i.e. 1 with the fixnum tag. and caddr will return 6, i.e. 3 with the fixnum tag.
2:20:44
aeth
The compilation model is also a weakness here. The compiler can't substitute (foo) with 1 (except within the file, which it might do if not notinline!) because FOO can be redefined at any time.
2:23:17
aeth
Finding a way to retore multi-file block compilation in SBCL could make a lot of this possible, but without a pure declaration, it would still be pretty easy to accidentally deoptimize your code.
4:47:19
pjb
LdBeth: in any case, you can always specify a specific element-type for your arrays. Perhaps the current implementation doesn't optimize it, but the next one will!
4:48:42
aeth
pjb: this has been discussed before and some of the element-types people might want (e.g. structs, if someone is used to C/C++/etc.) would be problematic to optimize
4:52:29
pjb
aeth: exactly. In the current implementations. But in the future it may be different. And it's a way to document the code.