freenode/#lisp - IRC Chatlog
Search
21:54:51
dacoda
I was wondering if it was possible to create an array displaced to another array of a different type
21:55:15
dacoda
For example, if I have one array of '(unsigned-byte 8) and I wanted to displace another array of '(unsigned-byte 16), is this possible?
21:55:28
dacoda
Otherwise, how can I re-use the data of the first array while interpreting it as 16-bit integers?
21:56:46
MichaelRaskin
I wouldn't expect this to work well, given that many implementations «tag» the data to keep track of types
21:57:43
dacoda
Hahahaha, that would be an interesting way around it! Just have a C function that takes in a uint8_t buffer and casts it to a uint16_t buffer, eh?
21:58:09
dacoda
I'm using it for a little toy script, and if that's the solution, I might as well write it in C
21:58:29
MichaelRaskin
Well, FFI has functions for direct manipulation of foreign memory, no need for the C function.
21:59:50
MichaelRaskin
Note that you give up any and all Common Lisp safety when you do foreign memory manipulations by hand…
22:09:27
dacoda
(let ((original (make-array 2 :element-type '(unsigned-byte 8) :initial-contents '(255 0))))
22:11:01
dacoda
Thanks for pointing me in the right direction, I'm going to mess around with this nonsense and see how it goes
22:11:18
dacoda
Ahhh, I wonder if the result of the convert-from-foreign is a new array or the same...
22:17:00
aeth
ah, I see, with-pinned-objects should behave similarly (but it isn't used in static-vectors)
22:45:24
aeth
You should probably use static-vectors because it's portable, but... I'm not sure if its implementation method in SBCL is better than yours and what the various drawbacks are.
3:48:14
akkad
Error: Reader macro conflict while trying to merge the dispatch macro characters #\# #\U
6:18:02
beardio
I use Emacs as an editor, started teaching myself lisp, bought ANSI common lisp and Land of Lisp. Came here to learn, while I work thru the exercises.
8:14:39
makomo
i need some advice regarding interpreter design. i have a "component" (concept of the object language, the one i'm interpreting) which stores variables within it. a component has multiple "processes" which contain code to be executed
8:15:46
makomo
i would like to be able to use arbitrary lisp expressions as arguments for certain instructions within the code of a process
8:16:35
makomo
putting all of the safety issues aside for a moment, what's the best way to evaluate this expression (which can be an arbitrarily complex lisp expression), but within a context where the variables within the component are bound
8:17:40
makomo
so for example, say we have a component with the variable a = 1 and we're executing the instruction '(format t "~a" (sqrt a)) within a process of this component
8:18:05
makomo
i disect the instruction, get to the argument '(sqrt a) and somehow EVAL this but within such a context so that a is bound to 1
8:18:50
phoe
I think your best bet is to construct an anonymous function form (lambda () (let (...) ...))
8:28:59
nirved
makomo: you might look at Let Over Lambda, https://letoverlambda.com/index.cl/guest/chap2.html
8:33:21
makomo
i just thought there might be a "prettier" way, but then again i'm not sure why i feel so wrong about it
8:35:31
pjb
In general code changes less often than data, so a compiled function is usually more efficient.
8:36:09
pjb
If you consider translating to compiled functions, then it may be more efficient to avoid the hash-table for storing the component fields.
8:36:30
pjb
Also consider that if you have less then 5 fields (or 35 in clisp), a a-list is faster than a hash-table!
8:36:33
makomo
pjb: in this case i'm generating code from data though. upon every evaluation i generate the LET that binds the symbols to their current values
8:37:10
pjb
That's the point. with eval you have to generate a new let form. But if the body doesn't change, it's not efficient.
8:37:32
pjb
Well, we already discussed it, there's no clear-cut distinction between interpretation and compilation.
8:37:52
pjb
But in a way, yes, we could say that I'd nudge you toward a transpiler. It's usually easier than a pure interpreter.
8:38:30
makomo
maybe that goes just for the first few steps and after that it just becomes a pain because of "issues" like the above?
8:39:29
makomo
right now i have 2 classes, one describes the component's class, the other describes the instance of this class
8:40:35
pjb
I guess it's time for you to read The Art of the Meta Object Protocol. https://mitpress.mit.edu/books/art-metaobject-protocol
8:42:30
makomo
pjb: although, i wouldn't need ability to add/remove slots at runtime in my case, i think. i would convert the component's description into a DEFCLASS and then instantiate a component by using MAKE-INSTANCE
8:43:22
pjb
Well, it depends if your "interpreter" is interactive or not, and whether it's possible to redefine the components.
8:44:35
makomo
true, but in that case, wouldn't it just reeval the DEFCLASS and redefine the class? i can't redefine components within a simulation so there's no danger of having to update objects of the old class
8:45:39
makomo
i.e. once the simulation ends, no instances of this class are stored anywhere anymore. redefining the class at that point should be easy right?
8:53:08
makomo
pjb: one thing that's problematic and that's stopping me from implementing a compiler is that these processes are like little threads which use cooperative scheduling
8:53:24
makomo
if i were to represent a process' code as a lisp function, how would i suspend and later on resume the function
8:53:35
makomo
i would need something like coroutines but that doesn't exist within lisp (there are libraries though) :^(
8:53:57
makomo
within the interpreter, i keep an "instruction pointer" into the list of the process' instructions
8:54:42
pjb
makomo: the lisp function doesn't need to match the structure and control flow of your source function.
8:55:15
makomo
that's true, i could generate some ifs or use a tagbody to jump to the point where i was suspended
8:55:18
pjb
If you use cooperating scheduling, then you would generate the lisp code in such a way that the function would exit each time it wants to relinquish the cpu.
8:55:49
pjb
There's an example of such a transformation in arnesi. https://common-lisp.net/project/bese/docs/arnesi/html/Automatically_Converting_a_Subset_of_Common_Lisp_to_CPS.html
8:56:21
pjb
Yes. You would enter the function multiple times. It can keep track of the state in a closure.
8:58:03
pjb
On the other hand, in this situation, I would consider generating lower level code to a virtual machine.
9:00:23
makomo
hm why? then i'm back to writing a VM which i wanted to avoid. i'm rewriting a C++ project, and i want to take advantage of being able to transform the component models into lisp and compile that
9:00:48
makomo
i could probably do both and compare though, but i'm interested in why you would use a VM
9:03:04
makomo
well, the models aren't that big usually, i.e. the number of processes is usually less than, say, 20
9:03:31
pjb
I find it easier to implement the semantics in a VM when the control flow is very different. You can run the VM step by step whenever you want, and do other things in between two steps.
9:04:16
pjb
Then either synchronize them to avoid parallelism, or let them lose to benefit from multi-core.
9:06:32
pjb
If you have i:=i+1 in one coroutine and i:=i-1 in the other, coroutines knowing they can't run at the same time, since they're scheduling cooperatively, you don't have any problem. But if you translate it to threads running on multicore, then you can have inconsistents updates of i.
9:07:18
pjb
In that case, you want to synchronize the threads so only one of them runs at a given time.
9:08:06
pjb
The advantage of using threads still, is that you have a stack and a PC for each one of them.
9:10:30
makomo
so there are 3 options, (1) a coroutines library, (2) threads and (3) do it manually by generating appropriate code and keeping track of state, basically replicating what (1) does for me
9:12:07
makomo
and since this gets compiled into lisp, any ideas on what (and how) debugging facilities to provide
9:15:38
makomo
on the topic of debugging -- providing stepping functionality to execute every coroutine until it yields would be trivial
9:16:09
makomo
however, providing debugging functionality to step over individual instructions within a process (i.e. on just on "yield boundaries") would take some effort and would require special support from the compiler right?
9:17:04
makomo
it would have to add special code to do a "special yield" after every instruction so that we can inspect the component's state and what not
9:17:55
makomo
these yields wouldn't be used to let another coroutine run, they would just pause the execution of the current coroutine for debugging purposes
9:21:29
pjb
This is what I do in cl-stepper, in that case, by shadowing and re-implementing the standard special operators or main macros.
9:39:25
beach
Currently, I use the term "code object" for an object that contains native instructions to be executed, but also information for the debugger and the garbage collector such as a mapping from values of the program counter to a register map, to source location, to live variables and where they are located, etc. But I am not happy with the term "code object", so I am looking for a shorter name. Any suggestions?