freenode/#lisp - IRC Chatlog
Search
20:36:42
pjb
(loop for 4elems in (com.informatimago.common-lisp.cesarum.sequence:group-by (iota 22) 4) collect 4elems) #| --> ((0 1 2 3) (4 5 6 7) (8 9 10 11) (12 13 14 15) (16 17 18 19) (20 21)) |#
20:40:43
pjb
_death: probably you will do something else than collect; Here collect is to show what's bound to 4elems.
20:55:23
makomo
is it possible to use slime's in-place expansion features to expand local macros such as macrolets?
21:00:21
phoe
with cursor on the last "foo" I get the correct expansion, (macrolet ((foo (x) `(+ 2 ,x))) (+ 2 2))
21:07:35
makomo
hmm, i'll have to check out all of the different macroexpansion functions slime provides
21:33:49
trittweiler
jmercouris, See pop-n at https://pastebin.com/PQHv4YJU - this will destructively modify the input and not cons
21:38:02
trittweiler
it goes through the list twice, though. Should store (nthcdr (1- ,num) ,old-head) in a variable tmp, then bind ,new-head to (cdr ,tmp) and change the setf down there to (setf (cdr ,tmp) nil)
21:41:15
makomo
this library i found today has some cool ones if you want to take a look and have some fun: https://www.hexstreamsoft.com/libraries/place-utils
21:43:24
makomo
phoe: seems like "macrostep" is the package i'm looking for (and the SLIME contrib which uses it, called slime-macrostep)
21:43:49
makomo
slime can do it by itself, but only if you use one of the *-all variants and by placing your point on the whole macrolet form
22:33:39
it3ration
I don't spose there are current bindings to vulcan / osx metal / et al for Common Lisp
22:42:34
aeth
it3ration: You probably don't want to use Metal. Just use a Foo->Metal wrapper like https://moltengl.com/moltenvk/
22:43:12
aeth
it3ration: As far as Vulkan goes, there's https://github.com/3b/cl-vulkan/ but it's incomplete because most people just use OpenGL via https://github.com/3b/cl-opengl/
22:43:31
aeth
For Vulkan's added performance to matter and be worth it (in exchange for added complexity) you need a very large application.
22:43:33
makomo
AeroNotix: WITH-RESOLVED-PLACES is also pretty cool, because it's basically ONCE-ONLY but for places -- it solves the multiple evaluation problem for subforms of a place
22:45:55
makomo
check out the example: https://www.hexstreamsoft.com/libraries/place-utils/#with-resolved-places
22:46:40
Bike
j`ey: usually we write loops so that continue isn't necessary- move conditions out, that kind of thing
23:09:53
AeroNotix
makomo: so glad I found this library! There are a few macros I wanted to write myself but couldn't be bothered ;)
23:23:19
phoe
this evening I have a functioning Qtools interface to its modernized and bugfixed version
0:30:18
makomo
Bike: on a second thought, WITH-RESOLVED-PLACES isn't exactly like ONCE-ONLY. the typical use case would be wanting to avoid multiple evaluation of subforms of a place within a macro -- for that you would use WITH-RESOLVED-PLACES within the expansion but with a gensym'd name for the binding
0:31:50
makomo
a place version of ONCE-ONLY would use WITH-RESOLVED-PLACES for you so you don't have to. in essence, WITH-RESOLVED-PLACES is like the LET within the final expansion -- the one that does the evaluation
0:32:07
makomo
i've created PLACE-ONLY, which automates that work: http://plaster.tymoon.eu/view/905#905 :-D
0:33:38
makomo
(...) like the LET at the beginning of the final expansion of a macro that uses ONCE-ONLY*
0:35:33
makomo
PLACE-ONLY and ONCE-ONLY have a lot in common. perhaps another higher-order macro should be made to avoid code duplication -- triple backquotes? :^)
0:38:12
AeroNotix
I'm surprised a lot of these weren't included in the standard. Especially things like updatef/applyf
0:41:33
makomo
true. it's also amazing how the setf expander machinery even allows you to design stuff like this today, a couple of decades afterwards
0:49:40
makomo
UPDATEF is almost like FUNCALLF, except that it doesn't take any extra arguments but allows multiple place-function pairs instead
1:20:14
makomo
are there any tricks to COND-like macros that would allow me to reuse certain variables from a COND clause's test-form?
1:20:34
makomo
for example, in order to test for a case i need to do an exepensive computation but also reuse it later on within the body of the clause
1:51:44
makomo
PuercoPop: unfortunately that introduces bindings which are visible to all of the clauses
1:54:18
makomo
COND-LET is found within "serapeum" https://github.com/ruricolist/serapeum/blob/master/control-flow.lisp#L338
1:54:42
aeth
Bike: but now it's time for a second-order pun, i.e. utility library for Common Lisp named after an ancient city because alexandria is
1:55:07
aeth
Bike: so even though there is no notable great library of Carthage, the name Carthage would be a fitting name for a utility library because alexandria is so notable
1:56:06
aeth
It actually got rebuilt and was one of the major cities of the Roman Empire. It would make a good name for a utility library because both Alexandria and Carthage were major Roman cities in Africa
1:58:40
aeth
Rome, Antioch, Carthage, Constantinople, etc. would make good names for CL utility libraries because Alexandria exists. Except, of course, if you called your library Rome it better be the best utility library in history.
2:01:11
makomo
hm, i'm wondering whether it's possible to create a "conditional place". it would be named IFF and would be used like (IFF cond then-place else-place)
2:02:10
makomo
the expander for IFF can do some merging of the expansions for the two places, but i'm not sure how to avoid multiple evaluations of cond
2:02:44
makomo
it would have to happen outside all of the expressions produced by the setf expander :^(
3:54:53
p_l
is it maybe the land of strong static types and dynamic scope for all practical purpose?
4:11:36
Fare
The types are often a big burden, but they do come with nice benefits when you learn to go with them.
4:15:24
ealfonso`
what is a recommended resource for CL best practices, like how to organize a project into packages, formatting conventions, linter?
4:24:55
ealfonso`
I wanted to factor out a youtube data api client library currently embedded into another project
4:27:13
beach
ealfonso`: I don't think there are any general guidelines. I use an ASDF file and a package file for each "module".
4:29:25
beach
ealfonso`: If you want an example, I am pretty proud of Cluffer: https://github.com/robert-strandh/Cluffer
4:30:48
beach
ealfonso`: It also contains tests using my favorite testing technique (random test against a reference implementation), and documentation.
4:37:00
aeth
ealfonso`: the three styles are generally one-package-per-file (sometimes combined with package inferred system), one-package-per-directory, and one-package and everything top level. The latter two are the more popular styles.
4:39:37
aeth
ealfonso`: The compiler usually fills the role of the linter. Indentation is usually enforced by the editor, which is usually Emacs.
4:40:46
ealfonso`
I can look at a project like hunchentoot or beach's recommendation Cluffer as guidance. aeth that makes sense
4:41:22
loke
ealfonso: there are multiple packages conventions. My recommendation is that you create a single package for your project, and never IMPORT (or :USE) any packages. Always refer to symbols in other packages by a full PACKAGE:SYMBOL name. THat will reduce any problems.
4:43:04
buffergn0me
Random tests against reference implementation is such an awesome thing to do whenever you can
4:43:16
beach
loke: Why a single package? I think that depends on the size of the project. Even for a modest-size project like Cluffer, I have 8 packages so that each "module" only exports its protocol.
4:44:06
beach
buffergn0me: It is very powerful, yes, and it saves a lot of time trying to enumerate all test cases manually.
4:44:51
beach
Right. I always prefix my package names and ASDF system definitions. Like in SICL, they are all named sicl-* and in Cluffer, they are all named cluffer-*
4:46:09
aeth
Iirc the style ASDF/UIOP prefers is foo/bar rather than foo-bar. So if the package represents the directory bar for the project foo, it would be foo/bar.
4:46:12
buffergn0me
Parenscript had a package named "JS" for a long time. Well of course JavaScript came out and also had a package named "JS"
4:46:19
loke
beach: Because one has to have a reasonably deep understanding of packages to make that work. Packages are actually quite difficult to understand for beginners, even though the concept is actually remarkably simple.
4:47:07
buffergn0me
Glad I got rid of "JS" from Parenscript, still feeling bad about having a "PS" package though
4:50:07
buffergn0me
Also don't forget about the Java-style naming convention for packages. Another option
4:50:37
loke
buffergn0me: without package nicknames (not supported by all implementations) java-style packages are horrible.
4:50:41
beach
One neat trick is to do what Common Lisp itself does and also CLIM. There is one package that contains only the symbols that are exported. Then there are potentially several "implementation packages" that provide the real definitions of those symbols. But any symbols naming helper functions, helper classes, etc., are strictly private to the implementation packages.
4:51:45
beach
That way, the "implementation packages" are totally independent and can be maintained separately without any risk of stepping on helper symbols in other implementation packages.
4:53:10
beach
So in SICL, to name an example, I have packages like sicl-clos, sicl-boot sicl-reader, sicl-printer, sicl-loop, sicl-format, etc.
4:54:02
loke
beach: with multiple backend “private” packages there is the question about which “private” sumbols should be exported though
4:54:33
loke
Because there is no way you can make a private package, well, “private”. That means that any exported symbols from a private package becomes candidates in code completion.
4:55:06
loke
I have resorted to using :: when having cross-package references between private packages. It's not ideal.
4:55:28
loke
CLIM works around it by having almost everything stuffed intop a single clim-itnernals package.
4:55:48
beach
Like in sicl-loop, I export symbols that allow for customization of the LOOP expansion.
4:56:04
loke
beach: True, no rule. but... once they are exported, they end up being proposed in the symbol-completion of SLIME
4:56:55
loke
beach: But what if I have two private packages, let's call then FOO and BAR... Now I have some functions in FOO that BAR should see, but they should never be exposed to regular users.
4:56:59
beach
The CLIM solution with a single implementation package is not ideal, because it defeats the independence I was referring to.
4:58:28
loke
beach: right. that's pretty much the point I was trying to make; the package system could be better.
4:59:17
loke
If only the implementations I use supported it... That's currently SBCL, ABCL and ECL (and sometimes CCL)
4:59:21
beach
"<bla> is not good in Common Lisp. We need an improved standard! Why did the creators of Common Lisp not think about that?"
5:00:40
beach
All I can hope for is that, once SICL exists, some of the techniques I use will be also be used by other implementations.
5:00:42
loke
beach: I know. I was just lamenting the fact that implementations are not following your lead here.
5:01:18
beach
loke: It would require some significant work, so I can understand why they would be reluctant.
5:02:14
beach
loke: Using my fast generic dispatch might make it more practical to use generic functions, so that the implementation is more modular. That, too, will require a lot of work in existing implementations.
5:08:12
beach
The fundamental problem is that existing implementations are not very modular. Fundamental implementation decisions are scattered all over the code, as opposed to being isolated in separate modules. Therefore, changing one of those decisions requires looking at a large part of the code.
5:09:50
beach
Plus, for bootstrapping reasons, some code might be written in a subset of Common Lisp, like the compiler not using generic functions, for instance. Such restrictions make it very hard to work on the internals.
5:54:58
jackdaniel
recently on cl-pro mailing list there was a suggestion, that dividing software into multiple packages gets in a way of the programmer
5:55:41
jackdaniel
I don't have a strong opinion on that topic, but there certainly is a merit in a claim, that juggling packages may be tedious and confusing (i.e answering the question "what is where?")
5:57:00
jackdaniel
loke: chaotic development (i.e without a centralized "lead") has some profound qualities, i.e it is more reisistant for mistakes and it grows in many different (competing) directions
5:57:18
jackdaniel
then you are able to "pick" something what suits you best, or there may raise a consensus what is "the right choice"
6:20:05
buffergn0me
Another thing to consider is breaking up packages along domain specific language boundaries.
6:38:51
aeth
jackdaniel: I :USE internally even though USE in general is discouraged, so that gets around the major inconvenience of separate packages.
6:43:03
aeth
I have some macros that greatly cut down on exports. It's mostly just the one macro for defining with-foo-accessors. (with-foo-accessors ((foo foo) (bar bar)) ...) behaves like with-accessors, except it will intern and prefix the accessor, so it's really (with-accessors ((foo foobar::my-foo-foo) (bar foobar::my-foo-bar)) ...)
7:07:15
_death
also, I find that with-accessors is a bad idea on several counts.. it's meant to lessen verbosity, but is itself verbose.. it's an under-the-carpet macro since the verbosity is a symptom of bad interface
7:09:07
aeth
_death: having foo::bar internally in a macro is perfectly okay as long as it doesn't fit in any of the cases that makes (gensym) necessary
7:09:54
_death
aeth: yes, but it means the user doesn't distinguish between external and internal symbols.. so no point in packages
7:11:53
_death
it loses the idea of symbol identity, since the second symbol in the "binding" is used only for its name in another context.. this makes it difficult to distinguish internal and external, and to extend as well
7:17:05
aeth
_death: Extensibility is a valid criticism of this sort of approach, but these aren't really meant for outside use. This gets around exporting issues when using many *internal* packages.
7:17:47
aeth
Extending these internal structure-objects and standard-objects will almost certainly break something.
7:19:03
aeth
_death: make a package for every file and you soon find yourself writing packages with literally dozens of exported symbols
7:22:19
aeth
Consider window settings. There's title, width, height, fullscreen, vsync (if graphically accelerated), etc.
7:22:31
aeth
e.g. https://gitlab.com/zombie-raptor/zombie-raptor/blob/63e9a3906476b1e54040597e45636fd2da6c3417/core/settings.lisp
7:23:03
aeth
I mean, I could probably split that into (for example) three objects, but that just means I either pass in 3 objects instead of 1 or I have one object-of-objects and now have 3 more accessors!
7:23:51
aeth
I think most Lispers just would use a dozen global special variables, which is even more problematic
7:25:12
aeth
Notice that each element in the struct has a :type argument. This is checked reliably in some implementations. The plist approach would require a CHECK-TYPE at moment of access from the plist, in a different part of the program.
7:25:30
aeth
There's just a ton of complexity in a game engine, no matter how you choose to arrange it.
7:26:22
_death
if you want to deemphasize symbol identity, you can use keywords which is very easy to see the pros and cons of.. a macro like with-foo-accessors lets you "feel with but go without" (not sure about the english idiom for this..)
7:29:45
aeth
If I used keywords to abstract over struct and standard-object accessors, I would have to write a considerably more complicated macro than with-foo-accessors, and without the benefit of the reader basically seeing what I mean just by the name of it.
7:30:36
_death
but the point is that you don't access your settings by having an accessor for each one
7:32:43
_death
you don't need to do type checking at each access.. you can do it when you create or modify the object
7:33:08
aeth
Do you want zombie-raptor/core/settings:settings-title, an explicit import-from for the 5 settings you happen to access in that package, the package to :USE that package, etc? Pretty much every way to access is messy.
7:33:43
aeth
And I use zero special variables (besides redefinitions of *standard-output*/etc.) because they don't play nice with threads.
7:37:30
aeth
I had weird things happen with special variables and threads. Now I just take the extra few minutes to pass objects around and get better performance and a clearer idea with what's going on.
7:38:31
aeth
It actually isn't that big of a deal to pass a variable 6 levels down a call-stack as special variable proponents claim.
7:39:26
aeth
standard-output is essentially irrelvant 95% of the time, so it would just pollute the API
7:41:21
aeth
That means that I would have to write my application with the assumption that the settings could change at any moment to anything.
7:42:58
_death
you are right that this is something to think about.. you can tell the user not to do that (this isn't java after all :).. or you could actually handle it correctly.. think Cells :)
7:44:19
_death
or are you saying that you just won't pass a settings object there.. which then make it troublesome to inspect settings
7:45:30
aeth
_death: the easiest way to inspect this is to recompile a function to insert a (break) in the middle of it ime
7:45:56
aeth
otherwise there would be dozens of objects (not just settings) that would need to be saved into debug globals
7:48:57
_death
in short you choose not to use the mechanism of special variables for something they are quite useful for (context).. many programmers do that, usually because they lack that mechanism.. and then there are programmers that make a conscious choice.. I think we can put Schemers in that category
7:50:00
aeth
_death: Special variables means that the whole program and all outsiders access settings. A settings object means only the functions that are passed the object (and, obviously, the programmer if debugging or whatever from the REPL) access it.
7:53:37
_death
this is a familiar argument (protect the programmer from himself) and we can agree to disagree about it.. there is a small technical point that the special variable has a name like *settings* which may be imported or not and so there's a way to indicate use or not use
7:55:49
aeth
_death: The programmer can do whatever they want in the CL environment, including access private things. This makes tests a lot easier to write, for instance. It also helps with REPL-based debugging, even though it might be annoying to write out a full package followed by ::
7:57:15
_death
aeth: right.. and a special variable is transparent.. things that don't use it don't need to pass it around.. unlike a settings object where you need some non-users to pass it around to users
7:58:38
_death
aeth: and internally, there's also the need to pass it around.. like I said, this hurts interactive development
7:58:41
aeth
_death: in my architecture, everything's passed into the init. The programmer owns the data. I don't even support reading in textures. I might eventually but in all of my tests that needed it, I just load in a PNG myself.
7:59:13
aeth
_death: Since the programmer passes everything in, the programmer can save it into a special variable first
8:01:07
aeth
_death: That's also why I prefer structs with typed-slots or standard-objects with a metaclass that ensures that preconditions are held. I want errors to happen before passing the data in.
8:01:34
_death
vsync: does the number #x3DA says anything to you.. (maybe a more indicative notation, &H3DA)
8:06:41
vsync
wonder if you could get ultimate frame rate by inserting a tiny flicker at some frequency
8:08:55
p_l
ACTION notes that all of the data channels in visual path are continuous wave with various levels latency involved in processing them
8:10:13
_death
vsync: it was the port of the VGA status word register.. to wait for vertical retrace you'd wait for the 3rd bit to be set there
8:34:35
shrdlu68
Running `sh make.sh` in the latest SBCL tarball from github says it can't run `git describe`.