OK, I’ll put that on my to-do list!
What would you like to see in uLisp in 2023?
I’d love to have a tutorial on a simpler way to extend ulisp.
If this could be done somehow in the builder, where I could add the external library functions in one place, I’d be thrilled!
@devcarbon I assume you’ve already seen this: Adding your own functions.
It’s pretty simple, but I agree that it could be simpler; for example, if all the extensions could be put in a separate source file, and automatically incorporated if that file is included in the build. I’ve thought about how to achieve that, but it’s a bit tricky…
I don’t think the builder is the answer; that’s something I created for my own use, and it’s not really user friendly.
@Pixel_Outlaw Thank you for your comments about uLisp! I’ll think about whether it would be possible to implement macros, at least a subset.
Hello,
I just wonder if it would be possible to run uLisp on top of the Nordic nRf9160. So you would be able to natively reach lte-m or nb-iot networks.
I was checking some forums and it looks like the only supported platform is the Zephyr Os. Would it be possible to add a feature or function or manual in order to run it there?
Thanks a lot!
I don’t think there is. I think @chamobit was trying to asking if there is ulisp support for other frameworks, or rather the Zephyr framework in particular. Maybe ulisp zero would? I can’t remember if it requires an adruino core or not.
I am a little curious how much would need to change to not be dependent on the arduino core.
So here’s a thought, granted it is probably far-fetched, but I think it would be really cool for ulisp to also optionally compile down to c/cpp in a way similar to microscheme. https://ryansuchocki.github.io/microscheme/
So you could interactively develop in interpreter mode, and once you’re done, compile to c/cpp with whole-program optimization.
Currently uLisp depends on the Arduino core for all the hardware interface support, such as digitalwrite, pinmode, with-spi, with-i2c etc. To not be dependent on the Arduino core one would effectively have to write an Arduino core within uLisp.
You can comment out all these functions, in which case uLisp will not be Arduino dependent. For example uLisp Zero is Arduino agnostic.
uLisp as a Library + Outside of the Arduino IDE (PlatformIO, etc)
Hello,
It looks like there is not support for nRF9160 :( at least not officially as per this.
" Zephyr has some documentation on how to include third-party libraries here and here.
But I would assume it depends on how “arduino-y” the library is. Zephyr doesn’t provide the Arduino runtime libraries etc.
We don’t support nRF9160 development without Zephyr RTOS so if you go this route, there is a lot of Nordic provided support that won’t be available to you"
Best Regards
Excellent, thank you very much!
Here is some nice documentation on them. (Though you are probably familiar)
https://cl-cookbook.sourceforge.net/macros.html
Backquote from there might be a good low hanging fruit initially.
Thanks for the link. That’s interesting but seems quite esoteric - can you suggest a macro that an Arduino user might want to write, for something that couldn’t be done any other way?
To get the ball rolling here’s an example I’ve thought of:
A C programmer would like to extend Lisp with a for-loop construct so they could write something like:
(defun test ()
(for ((i 0) (< i 10) (incf i))
(format t "~a ~a~%" i (* i i))))
Here’s the Lisp macro that would achieve this:
(defmacro for ((init condition increment) &body body)
`(let (,init)
(loop
(unless ,condition (return))
,@body
,increment)))
It could also be written slightly less elegantly without backquote like this:
(defmacro for ((init condition increment) &body body)
(list 'let (list init)
(append
(list 'loop (list 'unless condition '(return)))
body
(list increment))))
Just to clarify: the above code doesn’t currently work in uLisp.
Yep that’s the case for a macro!
Here is an actual one I would have liked when I was playing with the minesweeper clone on my Raspberry Pi Pico.
Macros are special because they delay evaluation, so in the body there (&body is the same as &rest) you can see I delay evaluation until I’ve wrapped and bound the required dotimes around it. This new form with-iterators is something you would have to implement in C. However with a macro I’d be able to have my cake and eat it too without burdening you. :) There are some gotchas for the programmer on the user side like unintentional capture and multiple evaluation. But to me this is a very powerful feature with countless uses beyond my loop below. :)
The nice thing about this new form is that it grows in a linear way avoiding manual nesting. The programmer (me) doesn’t really care that it generates nested dotimes I really only want to specify iterators - so a macro is born.
I’m not much of a C guy but I do know that nearly all Common Lisp dialects are implemented in it.
There might be some source code in ECL, Clisp, GNU Common Lisp or SBCL.
But the SBCL guys are doing some heavy voodoo for speed. I think some of the heavy hitters in the CL might be willing to help out if need be, your dialect is pretty close to Common Lisp already.
You might even get some helping hands from the IRC channel #lisp on the server irc.libera.chat !
Anyway, yeah I think you’ve grokked the idea.
Very true!
Here is a good example the first post by Rainer Joswig covers it well.
I don’t think Lisp stores all past gensym’d symbols. They’re free to be garbage collected but it does increment a gensym forming counter when making them which uses that global counter to make the next gensym.
Now if the gensym C counter is very small for uLisp (byte?), perhaps it attempts to fill old holes before incrementing. I think technically they’re not to be reused but uLisp has small footprint needs. Also, the default gensym would probably work. The optional prefix is for the programmer but I’d imagine it creates yet another lookup table.
Didn’t mean to open a can of worms!
Up to you of course. :)
On the other hand, perhaps I already have (gensym) :)
This will not conflict with interned symbols if a user defines “g4”.
At that point it should see it and hop over, generating “g5”.
Even when you delete the old symbol from memory the counter holds until it wraps around (very unlikely).
At that (extreme) point, I believe it’d start filling gaps.
(defvar *gensym-counter* 0)
(defun gensym (&rest prefix)
"Generates new symbol, increments *gensym-counter* until empty is found."
(loop
(let ((new-sym (read-from-string
(concatenate 'string
(or (car prefix) "G")
(string (incf *gensym-counter*))))))
(when (not (boundp new-sym))
(return new-sym)))))
(symbolp (gensym "foo")) ; She's a symbol
(eq (gensym) (gensym)) ; They're unique
Maybe, based on summary of all completed projects, it would be possible to design a framework for a basic nano-satellite?