libera/#commonlisp - IRC Chatlog
Search
16:07:09
lisp123
If I want to load some elisp code for a program, I have two options. Either I get the end user to download and load the .el file themselves (which encourages them to tinker with it and improve it for themselves), or I can just do a slime:eval-in-emacs....I am leaning towards the latter as it reduces the installation process, any thoughts?
16:14:19
mfiano
Which has a similar piece of functionality, so you'll need to use read time conditionalization
16:15:08
lisp123
Ok, I will create a SLY front-end and make that adjustment....and also create some other front end for other users
16:16:27
lisp123
Actually thanks, this is very helpful. I will create an alternate version that works directly in the REPL, and leave the Emacs version there for those who want a slightly better experience
17:09:17
jmercouris
it always bothered me, maybe there is like a sethash in some library or something
17:14:06
jmercouris
Bike: well, I can push to a list, I feel like I should be able to push to a hash table
17:15:10
Bike
but that's what (setf gethash) does. is it just the order of arguments you don't like?
17:15:37
lisp123
hould the language have every possible gadget like this that anyone can write in a minute? In Common Lisp, there are included batteries, but they are other kinds of batteries: things that are actually hard to do. For example, a compile function for dynamically compiling code at run time. It would be prohibitively difficult for most users to develop such a thing from scratch compared to pulling keys or values from a hash table in half a doze
17:16:17
jmercouris
well, it's not a big deal, perhaps I am just procrastinating and not realizing it :-)
17:16:54
lisp123
Think of it as a feature ;) It encourages more programmers to write small bits of code vs. being spoon fed --> The end result making them better programmers
17:43:54
Guest17
saw the asdf post on reddit. I keep running into this perennial problem where I need to dump a program with asdf dependencies into another source tree such that anyone can check out the code and make the program from scratch as opposed to distributing it via the system package manager or as a quicklisp package.
17:44:35
Guest17
after reading that post, I figured that the only thing I really needed was to prevent asdf from searching the user directories for packages and only use one provided by project configuration
17:45:20
Guest17
additionally, in my particular case, it would be nice to keep the build objects (fasls) in the source tree in a particular spot, as that is where we put build artifacts of other code in this repo. That part I think I read in the documentation
17:45:57
lisp123
jcowan: I don't disagree, it can come across as an excuse - but everyone has different requirements, one person's sethash is another's setf gehash
17:47:04
Guest17
the way I see it, I can check in a whiole lisp distribution, like a checkout of a working ccl folder, the result of calling quicklisp bundle, ??? calling code to build a kernel+image ??? only using asdf packages found in the local directory and preventing the user directory defaults ??? profit
17:52:00
lisp123
Guest17: Not entirely sure what you are after, but if I recall correctly QuickLisp Local Projects might help
17:53:07
lisp123
Otherwise you just need to figure out where ASDF scans first (don't know off the top of my head) and put your .asd files there -> In general I think its better not to have multiple versions of the same dependency running around
17:53:27
Guest17
so my ultimate goal is that I have a work repo for non lisp code. I made a utility that I don't want to rewrite in common lisp. I want any yahoo that checks out the main repository to essentially run make and get my utility as a standalone program. My code depends on packages sourced from quicklisp and I know how to create a bundle of the
17:54:05
Guest17
right, the last part is important for repeatable builds, I don't want asdf to scan the default directories, in case someone like me has a local install of quicklisp
17:54:44
lisp123
Your users have Common Lisp installed I imagine and are CL users right, otherwise you wouldn't be sharing them the source code
17:55:51
Guest17
They don't, not yet anyways. Actually since we use ros, sbcl is pulled down as a dependency, so yes they all do ;-) but I'd prefer it if the build process didn't depend on any system-installed or user-installed files/packages, and that such things wouldn't get accidentally pulled in if they exist
17:58:01
Guest17
I know i've had issues with the fact that in ubuntu 16.04, many lisp packages are available from the apt repo, and those conflict with installing things assuming those aren't available (which I'm always doing)
17:59:38
lisp123
I'm trying to check the IRC Logs on that, I think that might be a better version of ASDF that could help you
18:05:29
Shinmera
There's also no way to scan for projects, or even define them outside of writing source code
18:09:38
jcowan
lisp123: That case doesn't bother me. But on that argument, why does CL standardize LENGTH? It's about five lines of code. The CxxxxR functions are even shorter.
18:11:17
jcowan
Sure. But the passage that lisp123 quoted claims that there is a rational argument for excluding functions with short definitions.
18:11:34
pjb
lisp123: symbols are string designators, and string= and string-equal take string designators…
18:12:49
lisp123
pjb: Thanks, I think I'm all good on Symbols today after my earlier confusion in the morning
18:13:31
lisp123
I am more or less finished on my autologging tool (based off IBCL), will share shortly for feedback and if anyone finds it useful
18:15:37
pjb
* The append keyword causes its list values to be concatenated into a single list, as if they were arguments to the function append.
18:15:37
pjb
* The nconc keyword causes its list values to be concatenated into a single list, as if they were arguments to the function nconc.
18:16:46
pjb
Indeed, nothing says that the implementation cannot optimize by keeping a reference to the last element, but note that since loop often cannot easily guess what will be the last list appended to the result, in the case of append it has to keep a reference to the start of the last appended list, to be able to copy if if a new one needs to be appended.
18:18:23
pjb
Both could also be implemented directly as: (loop collect list into lists finally (apply appender lists)) with appender = (function append) or (function nconc), and therefore defer the optimization to loop collect, and to the append and nconc functions.
18:21:09
lisp123
jcowan: I take back my earlier comment partly, there's no good reason for not having more standardisation as jmercouris queried earlier re sethash. However, I think "just write your own" is a fair response in the sense (IMO?) that seems to be one of the essential styles of programming in Lisp (reshaping the language to suit your needs)
18:22:00
pjb
I note that no implementation returns true for (let ((last (list 1 2 3))) (tailp last (loop for list in (reverse (cons last (quote ((4 5 6) (7 8 9))))) append list))) ; which means that they are all non-conforming: (loop append) doesn't behave like (function append)!
18:23:05
jmercouris
lisp123: well, sure, but the problem is not everyone will use whatever layer you design, the common denomenator is CL
18:23:12
jcowan
I agree with that, certainly. But I think it's worth standardizing trivial but commonly used things for two reasons: everyone will use the same name for them, and to avoid this problem: "Data type X would be optimal here, but I have a better library for data type Y, so I'll use Y.
18:23:17
jmercouris
so if you are using some super set of CL, in order for users who are not using your superset you have to be able to compile to CL
18:24:09
jcowan
Well, if it comes to that, every function and macro added to an image creates a superset of CL.
18:24:54
jmercouris
I guess I am thinking of things differently, because I am thinking in the context of Nyxt, which is a application framework
18:24:59
pjb
or any non-standard operator specific to the implementation. Including semi-standard stuff like the MOP, gray-streams or less standard stuff like ffi and sockets.
18:25:09
jmercouris
and I'm thinking OK, things that users build with Nyxt, how will they be broadly applicable to the CL community as well?
18:25:50
Bike
in this case the function at issue wouldn't just be short, it would be exactly another operator with its arguments permuted
18:25:50
pjb
jmercouris: if you don't hide the fact that some stuff comes from the CL package and some from a NYXT package, users should be able to write library code that only use CL…
18:26:05
Bike
at which point maybe there should just be mechanisms for doing that (like haskell has, off the top of my head)
18:33:19
lisp123
jmercouris: I assume you would have a fair bit of custom API for various widgets, so nyxt code writers will largely work with your standard library vs. CL?
18:34:09
lisp123
So as long as you document reasonably well, most CL users will be able to navigate through your codebase and figure out where you are abstracting away -> Thus, IMO write for the non-CL user
18:37:42
etimmons
Guest17: I think either CLPM or Qlot would help you out if you want semi-repeatable builds
18:37:45
borodust
lukego: bindings look smth like this: https://github.com/borodust/claw-linux-perf/blob/master/bindings/x86_64-pc-linux-gnu.lisp
18:39:01
etimmons
If you already use Roswell though you might lean toward Qlot, as it's fully embraced Roswell, for better or worse
18:39:48
borodust
lukego: i didn't test them though and they are also for 5.12 so if your pc blows up it's not on me ;p
18:41:17
lukego
are these rational numbers okay? https://github.com/borodust/claw-linux-perf/blob/master/bindings/x86_64-pc-linux-gnu.lisp#L508
18:46:25
etimmons
Guest17: it also rubs me the wrong way. I think probably because it tries to do too much
18:48:13
etimmons
Guest17: If you decide to poke at CLPM, feel free to jump to #clpm if you have questions. Also happy answering things here, so long as we don't swamp it
18:49:36
borodust
https://common-lisp.net/project/cffi/manual/cffi-manual.html#foreign_002dslot_002doffset
18:57:15
lukego
Just now I suspect that I'll use CFFI-GROVEL to resolve all my named enum constants to concrete values and then otherwise probably use NIBBLES to construct my foreign data. That wouldn't be a good strategy in general but I think makes sense here especially since there will be a bunch of other in-memory structures not defined as C structs at all iirc
18:57:23
etimmons
Any mods here also have a matrix account? Or are willing to briefly give mod powers to a matrix user?
18:57:47
etimmons
IRC -> Matrix messages appear to be broken because someone on the matrix side isn't fully connected
18:58:14
etimmons
It's a security feature (on by default) so that anyone sending a message on IRC knows who's all in the room when they send a message
19:37:43
q3cpma
Hello, does anyone know a way to avoid calling gethash more than once when you want to check the value before setting it? Maybe a way to store a place in a variable, or something?
19:40:30
_death
when you read from a hash-table, you use gethash, and when you write, you use (setf gethash)
19:43:48
q3cpma
_death: but I have to call gethash twice for each entry, and the standard obviously doesn't say the hash won't be computed twice
19:46:12
_death
a call to gethash is not the same as a call to (setf gethash), although it's true that the hash may be computed twice
19:46:53
q3cpma
Yes, but I think I might avoid this by using the setf-expansion to get the "reference"
19:50:20
_death
you could write your own hash-table implementation, although it may need some work to compete with your implementation's.. e.g., see https://lisp-univ-etc.blogspot.com/2018/01/minimal-perfect-hash-tables-in-common.html
19:57:15
Bike
i believe sbcl's hash tables do this themselves, i.e. they cache the last key so if they get it again they don't need to recompute anything
19:59:42
Bike
if you look at what you get from (get-setf-expansion '(gethash foo bar)) you can see there aren't any hashes in it
20:00:30
Bike
generally (setf (gethash foo bar) baz) expands into something like (funcall #'(setf gethash) baz foo bar) or (puthash baz foo bar)
20:05:41
q3cpma
From #clschool, someone solved my specific problems by pointing that the default optional arg of gethash was used with incf!
20:09:41
_death
the incf would basically be (let ((value (gethash ... 0))) (puthash ... (1+ value)))
20:10:08
pjb
q3cpma: the standard doesn't impose algorithms in general (only the lisp reader and a very few function algorithms are specified). But it is in general expected that implementations at least try to be as efficient as possible in the common cases.
20:10:48
pjb
Hence this optimization I mentionned to save the last entry in a cache in gethash, so that (setf gethash) doesn't have to recompute everything if you just used gethash before.
20:11:58
pjb
Not really. A lot of data structure benefit from a much clearer API when some caching is used.
20:12:10
_death
but the hash function may be very fast.. in other words, is this an actual performance problem you're having, or pie in the sky thinking about what hashing twice might incur
20:13:04
q3cpma
_death: I'm doing the word frequency exercise, of course I have to optimize it, or it doesn't make any sense
20:13:12
pjb
q3cpma: why would you care if an entry is computed twice anyway? gethash should be O(1) (ie. doesn't depend on the number of elements in the hash table).
20:14:18
pjb
Bike: efficient (incf (gethash key table)) depends on the implementation caching the entry it finds (otherwise it has to compute the hash of the key twice in a row, and to find the entry twice, once to read, and once to write it.
20:14:30
q3cpma
_death: _death: http://www.leancrew.com/all-this/2011/12/more-shell-less-egg/ the Mcllroy/Knuth thing
20:15:17
pjb
Bike: compare with (incf (assoc key alist)), where incf can do (let ((entry (assoc key alist))) (if entry (incf (cdr entry)) (push (cons key (1+ default-value)) alist))) without calling assoc twice (which is O(n)).
20:15:32
Bike
"Read a file of text, determine the n most frequently used words, and print out a sorted list of those words along with their frequencies" close enough
20:16:02
pjb
_death: the parameter that matters when we say that, is the size of the hash table, not the length of the keys…
20:16:34
_death
pjb: with ordinary hash tables, the amortized cost may be constant, but worst case cost is N
20:16:37
q3cpma
pjb: using O with hash tables is always tricky, as you can never be sure the bucket isn't getting a bit full.
20:17:11
pjb
_death: in particular, CL hash-tables have the threshold parameters, that hints at one implementation strategy: when the table becomes big (not enough holes), it size is increased and the entries redistributed. So CL hash-table can avoid bucket lists.
20:17:35
_death
pjb: for example, when there is a collision, the items in the buckets may be scanned (linearly)
20:18:15
pjb
and we expect the hash function used to avoid collisions. If there are, the threshold parameters ensure that there are enough holes, so that it's again O(1) (statistically) to find the slot.
20:19:01
pjb
This doesn't prevent bugs, eg. once clisp had a bug where the hash function used returned a value multiple of 4 (so that was very bad), but bar bugs, it's good.
20:19:16
q3cpma
I doubt it functions like that unless it uses a more complex strategy (e.g. cuckoo hashing)
20:20:59
_death
q3cpma: I'm not sure a hash-table is good for this problem, since you need the top items
20:21:00
Bike
rehashing doesn't make it constant time, does it? how long it takes to rehash depends on the size of the table. so you're back to _amortized_ O(1) _at best_ and worst case O(n). which is what death already said.
20:24:41
lisp123_
I have a related question --> How does this function work? (loop for key being the hash-keys of hash-table collect key)
20:24:54
q3cpma
Doesn't look optimal, I'd probably use something like FNV for small keys and maybe XXH for the rest; but well, it's okay
20:25:27
Bike
lisp123_: depends on the hash table implementation. sometimes the table is two vectors, one of keys; sometimes it's one vector with keys and values interleaved
20:26:37
_death
q3cpma: my question still stands though.. did you write the code, profile it and determine that the hash function is the bottle neck?
20:29:04
q3cpma
_death: didn't and I don't need to hear the old "premature optimization is the root of all evil", I know it. It's just a worry I got while doing a beginner exercise.
20:31:22
Bike
what would a hash table api with an option to use precomputed hashes look like? optional parameter to gethash? and then if you put in something that's not actually the hash it gets dumbly inserted there too, i guess?
20:33:18
q3cpma
Something like Tcl's dict update, where it executes code with a local variable, then use its exit value to write
20:33:18
White_Flame
but the EQ key cache should be common in CL hashtable implementations and deal with all that
20:33:52
_death
pjb: when you write O(...) it means worst-case, iirc.. for average/amortized cases you don't use big-O but phi or somesuch
20:35:19
pjb
That said, nothing prevents you to implement your own hash-table variants with the right properties for your case.
20:35:27
_death
pjb: it's important when you have deadlines (real-time).. so you would then prefer, say, merge sort O(n*lg(n)) over quicksort O(n)
20:35:58
White_Flame
but there are tons of options that emerge with this sort of combined API, that just having the basics suffices better
20:36:15
White_Flame
for instance, if there is no existing key, maybe you want to have different behavior than if one does exist
20:36:29
White_Flame
or have the option to remove the key within your read-modify-write operation, etc
20:36:51
pjb
_death: note that bubble sort on a sorted array is O(n), so it could even be better if our array is usually sorted.
20:37:03
q3cpma
Yeah, another thing that I don't like, is that SBCL's with-locked-hash-table seem to lock the whole table, and not just the bucket
20:40:01
_death
q3cpma: basically for this problem I'd say you want a priority queue (which can be implemented, say, as a heap of some kind)
20:41:38
q3cpma
_death: hmmmm, how would that work with strings? Doing log(N) string comparisons sounds dreadful.
20:43:20
pjb
q3cpma: that said, usually you have to have a lock outside of the hash-table, hash-table locks are quite useless IMO.
20:43:39
White_Flame
you could intern string themselves, or if they don't have very many shared prefixes, failure comparisons will be quick
20:44:18
pjb
hash-table locks are ridicuous: (progn (decf (gethash src-account accounts) transfer-amount) (incf (gethash dst-account accounts) transfer-amount))
20:45:10
White_Flame
and the (incf (gethash ...) ...) doesn't hold a lock between the read & the write
20:45:46
_death
q3cpma: of course CL already gives you hash-tables and sort.. and it'll likely be fast enough (even if a hash-function gets called twice...)
20:45:50
pjb
The point is that if you have multiple threads, there will be other data to include in the mutex, not only the hash-table entry.
20:49:15
Alfr
_death, I doesn't matter whether your analysis is armortized or not. O(f) means there exists A for all sufficiently large X we have g(x) < A*f(X).
20:51:42
Alfr
_death, in contrast big theta means that's g is also bounded below by f, i.e. additionally there's B f.a. large enough X s.t. B*f(X) < g(X).
21:22:36
White_Flame
~/quicklisp/local-projects/ can have symlinks or subdirs that will be quickloaded
21:23:11
White_Flame
or there's asdf:*central-registry* but you need to have init code that feeds it on every launch
21:38:23
White_Flame
seok: no, there's a ql: call to update/refresh the registry, if you've changed the local-projects during runtime
21:43:15
pjb
seok: and not asking the same question in multiple channels. See the answer in #clschool
0:19:29
Guest17
found https://common-lisp.net/project/asdf/asdf.html#Controlling-where-ASDF-searches-for-systems this. looks like I can just define an environment variable for it at build time
0:46:53
phantomics
Hey everyone, is there a preferred library/macro to write paths for getting contents of nested plists? Like (get-lpath list :a :b :c) instead of (getf (getf (getf list :a) :b) :c)?
0:53:27
mfiano
Can someone remind me of the extended keyword parameter syntax or point me to the relevant section?
0:53:54
mfiano
I would like to write a method for #'shared-initialize that accepts non-keyword-interned &key arguments
0:54:13
phantomics
But they mention that performance isn't their priority, in my case I know I'll always be using a plist so I could just write a macro for that case myself
0:57:05
mfiano
So reading this, am I correct in that in order to supply a non-keyword keyword-name, I must explicitly specify the initial value form?
1:00:50
lotuseater
but (&key (a '())) would be helpful, so one knows from reading that there should go a list
1:02:40
lotuseater
mfiano: and maybe you remember also that you can give a specific keyword predicate too as a third component
1:02:42
mfiano
In this case I have several methods defined on #'shared-initialize specializing on classes that are intended to be abstract mixin classes.
1:03:40
mfiano
To define these classes, a defclass-writing macro is used (instead of defclass), which canonicalizes some things. For example, specifying keyword-interned initargs has a high liklihood of clobbering sibling mixins
1:04:16
mfiano
So I must also be sure to do so in shared-initialize/reinitialize-instance/initialize-instance/etc
1:07:28
mfiano
This is a complicated project I've been writing the design down for like 2 months now. Maybe one of these days said design will be solid enough to implement :)
1:13:12
lotuseater
_death: hm just a minor, wouldn't it be: (defun foo (&key (a b)) (list b)) (foo :a 42) => (42) ?
1:14:08
mfiano
I read AMOP recently, and the authors made a seemingly bold claim that the MOP solves the problem in that no longer do you have to choose flexibility over performance. Anyone that knows the MOP knows that is not _all_ that bold :)
1:14:45
_death
lotuseater: your form has a different meaning.. it defines a FOO function with a keyword parameter named :A, a corresponding variable named A, and a default value form B
1:18:19
mfiano
&key ((a b)) means that the argument will be 'A and the parameter will be B, and bound to NIL if the argument is not supplied.
1:18:30
_death
lotuseater: in the sub-section for keyword parameters, an example is given that shows the corresponding long syntax for the short syntax you used
1:19:11
lotuseater
ACTION is very happy to be allowed being around so many very capable people, honestly
1:26:08
lotuseater
hah from our discussion i tried a simple class slot with ":initarg name" so an instance value for this is given by "'name \"foo\""
1:30:40
mfiano
More like trying to piece pages of my thoughts together on paper before I write the next module
1:33:46
lotuseater
mfiano: your "[ab]using to the limit" gets me to the song "Push it to the limit" ^^
1:35:49
mfiano
Naming things is hard, especially when the minimum description that conveys meaning is overly verbose.
1:36:48
mfiano
overly verbose wouldn't be a problem if it weren't for a high-frequency client interface
1:42:47
mfiano
Designing and coding is usually easy in comparison with nomenclature. I would probably be a good mathematician if I gave it as much attention.
1:45:49
lotuseater
so before (define-symbol-macro thing (gensym "THING")). this would be a line in the book "How to screw things up with elegance"