libera/#commonlisp - IRC Chatlog
Search
18:58:02
rotateq
like when a popular python tool is replaced but the API and superficial look leaves to be the same :)
19:26:47
lisp123
With sly, everytime I exit sly-db, it asks me whether I want to throw to the toplevel (y / n), is there a way to set this to y always?
19:29:35
lisp123
there's a clash between EVIL mode & Sly, so will need to fix that, but otherwise all good
19:48:02
Bike
say we had the code (let ((a (foo))) (map nil #'print a) (aref a 0)), and at some particular time FOO returned a list rather than a vector. how would people feel about an implementation that signaled a type error as soon as the list was returned, i.e. before doing the map?
19:51:05
edgar-rft
I would expect AREF to signal an error (after the MAP), not at the time of the the LET binding
19:54:09
Bike
that's how it usually works now. i'm asking how people would feel if it worked as in the hypothetical.
19:58:49
White_Flame
Bike: would that be because the type inference from aref hoisted up for the whole body?
19:59:38
White_Flame
I think that would be the actual consequence of what "type inference" means. It's about A itself
20:01:14
Bike
it would be inferring backwards from the fact that (aref a 0) is undefined unless a is a vector, yes
20:02:31
Bike
as far as i'm aware, no actual implementation does what i'm describing. they might issue a type warning at compile time if foo is declared to never return a vector, and probably signal an error from aref if it receives a non vector
20:03:25
White_Flame
with high safety and debug, are there runtime warnings when type declared bodies are entered with the wrong value type?
20:12:09
Bike
sbcl will signal an error if there's an explicit type declaration, but not for my example
20:17:05
jeosol
When writing a paper about CL, what is the canonical reference for CLOS in terms of reference citation
20:19:59
jeosol
NotThatRPG: Thanks, I think you are right. I remembered I have a copy of "OOP: The CLOS Perspective" and that is what they cited too for CLOS
20:20:43
NotThatRPG
jeosol: I think it depends on whether you want to give credit to the people who developed CLOS, or just point someone at an explanation of what CLOS Is.
20:21:44
jeosol
good point. But it's more as a reference too for people to understand what I am refering too. Lispers probably does but it's making adding reference appropriately
20:22:29
jeosol
I use SBCL primarily, so not sure if there is doc for SBCL CLOS(?) but I imagine since implementations are mostly compliant, I don't have to cite any specific to SBCL just that higher-level should cover everything
20:23:13
NotThatRPG
So if your readers are not familiar with CLOS the Keene book might be a better citation (or compromise and give both)
20:29:31
jeosol
Keene's book was what I read front to back to understand CLOS so it is definitely useful, guess for non CL folks
20:47:11
Bike
if you want arbitrary element type, you'll have to use (simple-array * (*)) rather than simple-vector (which is (simple-array t (*)))
20:49:45
pjb
Bike: obviously, the bug is in aref: (let ((a (foo))) (map nil #'print a) (elt a 0)) will work for any sequence returned by FOO.
20:50:17
mfiano
struct types. These aren't immediates so I can't really store any simple-array that is not of type T. SBCL says it is a simple-vector
20:54:42
phoe
but arrays of structs can't because of identity issues - I remember discussing that problem some time ago
20:54:46
Bike
it is unlikely that anything but numbers or characters will have specializations, due to how eq is defined. yes.
20:57:42
mfiano
Yes I have cheated and boxed a ub64 return value inside a 0-d array when the caller couldn't inline the function...
21:00:53
mfiano
So how do the type specifiers SIMPLE-VECTOR and (SIMPLE-ARRAY T (*)) differ exactly?
21:07:34
Bike
it's a little bit more complicated. the standard says that a non-adjustable non-displaced array with no fill pointer is a simple array, but it doesn't say that a displaced array or etc is _not_ a simple array. so like, an implementation could say all arrays are simple.
21:18:15
mfiano
Admittedly I am too used to static analysis of SBCL with regard to arrays of varying types, and it maps very well to my mind with what the machine code will look like.
21:27:44
mfiano
I'll probably stick with the runtime check though. I would have to greatly change the load order of my code, as this is for a struct definition that needs to be loaded earlier than the structure-objects the elements of this slot will contain
21:29:38
mfiano
Normally I would use standard-objects, but this is very low-level code that I am doing the early 75% optimization that doesn't take too much time and will more than pay for itself. It's the other 25% that is not going to happen.
21:32:20
mfiano
Which would still be a runtime check. I am getting into a hole I don't want to be in, so simple wins the race.
22:34:08
morganw
Hopefully this is not too much of an annoying beginner question, but I'm following exercises in a book and accidentally made a function which remembers its previous let binding values. Could anyone point me at the mistake? https://pastebin.com/R5x5DBtN
22:39:12
morganw
(count-bases '(a g t a c t c t)) or (count-bases '((g c) (a t) (t a) (t a) (c g))) are the given examples to work with.
22:43:33
morganw
Basically, just count the symbols in either case and return the counts. I thought I was being smart and efficient by modifying the return list in-place, but apparently I'm not that smart... It does work on the first run but somehow the ret list is preserved for the next run.
22:47:15
morganw
(in the chapter about iteration, so the function is meant to be iterative in how it works even when the problem doesn't naturally fit)
22:51:01
rotateq
(loop named count-loop with as = 0 with cs = 0 with gs = 0 with ts = 0 for symbol in list when (eq symbol 'a) do (incf as) when (eq symbol 'c) do (incf cs) when (eq symbol 'g) do (incf gs) when (eq symbol 't) do (incf ts) finally (return-from count-loop (values as cs gs ts)))
22:51:35
rotateq
but watch out, the T will really be seen as the top-value too, but okayish in this case
22:53:12
rotateq
okay, value 'true' but highest system-class top or better ⊤, the T is just by accident similar taken as 'true
22:54:06
morganw
Just to double-check, if you run my function does it also remember the previous runs? (just to check I haven't somehow broken the whole environment)
22:55:24
_death
morganw: you shouldn't modify literals.. the result of '(a g t ...) is a literal. instead, you can use (list 'a 'g ...) or copy the list to create a fresh one, (copy-list '(a g t ...)) .. you can also use copy-tree to copy the sublists in the second one
22:56:41
pillton
morganw: "The consequences are undefined if literal objects (including quoted objects) are destructively modified." from the CLHS entry for QUOTE.
22:57:01
_death
oh, I didn't look at the paste.. the literal you modify is '((a 0) ...) so you can use copy-tree, or simply variables and construct a list when returning
22:57:24
rotateq
i would have said, that better do it with (let ((%a 0) (%c 0) (%g 0) (%t 0)) ...) and you won't get a headache for your SETF forms
23:16:18
rotateq
today i had a thought to something of mine "so this is the prototype for the prototype" :D
23:38:20
morganw
It is that book. But it seems that part of the learning process is being restricted to certain methods in each chapter.
23:43:23
morganw
Order of chapters is first learn about applicative methods, then recursion, then iteration.
23:44:22
morganw
I imagine after this chapter I'd actually be free to pick the most appropriate way to suit the problem. No mention of loop yet though.
23:53:32
NotThatRPG
TBQH I prefer to use the ITERATE macro over LOOP because it's not a separate language like LOOP (also LOOP has some specific defects in terms of conditionals and handling multiple values)
0:15:22
aeth
I don't like ITERATE because it's not LOOP-with-parentheses that people promise when they compare the two
0:15:35
aeth
And if I have to learn it to use it, everyone else will have to learn it to read my code.
0:18:42
aeth
If you don't have to collect (or similar) you can just use CL:COND or whatever, but if you are going to use collect, you suddenly need to use LOOP's if/else system
0:19:28
moon-child
raku and mathematica have gather/take, which are better because they compose with the rest of the language
0:20:00
aeth
again, sounds like something that would require special training, making code that only you can read
0:20:34
aeth
all I want is a hypothetical, e.g. called DO-LOOP, that uses parentheses in a way that makes it fit in... every other feature the same except perhaps for a few things that break the syntax too much
0:22:16
aeth
most of LOOP, parenthesized, could be turned into trailing plists. A few parts couldn't, e.g. the hash table stuff that uses multiple symbols in a row
0:22:42
aeth
once you have things as parenthesized and key/value plists, you have a reason to use it: extensibility
0:24:06
moon-child
sure. It might more might not be _better_, but I think it is definitely not _significantly_ better
0:25:07
aeth
(to anticipate being poked 5 hours from now... OK, a DESTRUCTURING-BIND or an APPLY, depending on how you'd want to do it)
0:26:50
moon-child
(in case anyone cares, here is my loop extensions wishlist: collect into string/array, collect major cells of multi-dimensional array, resulting-in clause, bind multiple values)
0:28:08
aeth
otherwise you have to cons up an intermediate list or give up half of the convenience of the LOOP form
0:28:53
aeth
I usually just PSETF at the start of a DO in the body when I need multiple values iirc.
0:30:01
moon-child
well, I mean--it's all convenience features, I don't think any of these are particularly _important_. Can just PROG like it's the 60s
0:31:17
aeth
not having a M-V-B seems to be the main flaw, as well as no collect-into-array (which means you have to manually track the index)
0:32:49
moon-child
NB. I suggest SELECT, VOLITA, and VOLITAS for strings, array elements, and array major cells, respectively.
0:39:12
aeth
moon-child: collect-into-array at an implementation level of CL:LOOP (so you couldn't do it yourself) could be unsafe
0:39:39
aeth
at least, if you want a simple-vector at the end (which requires copying, unless the implementation optimizes it, which they won't)
0:41:41
aeth
i.e. an adjustable vector only when creating it, and then once returning it it becomes a simple-vector. This requires implementation-level support afaik
0:44:38
moon-child
(also would result in arguably odd behaviour; (let (x) (loop repeat 1 volita 5 into y do (setf x y)))
0:55:49
aeth
moon-child: no, it could be implemented portably, it just couldn't be optimized portably... it would have to be optimized at the implementation level
0:56:07
aeth
moon-child: I just told you the portable implementation... SUBSEQ at the end to turn an adjustable vector into a simple-vector
0:58:45
aeth
you could just have into not apply to collect-as-array, except perhaps if that variable is only accessed inside of a finally
1:02:13
aeth
except anyone who optimizes array code turns their function into one that only accepts a simple-array, for "free" optimization at the cost of breaking, well, this
1:03:06
moon-child
I would rather have whatever implementation-specific functionality is required to turn an adjustable array into a simple vector be exposed explicitly
1:03:53
moon-child
(with a portable fallback to SUBSEQ, presumably--it is not necessary to retain identity, and may even be impossible with certain tagging schemes. As with other destructive functions, the source may be left in undefined state)
1:05:20
aeth
It's specified to return a simple array of the rank, anyway. And as you see, it doesn't need to return the whole thing, so you only need to track the end point
1:06:19
aeth
If you wanted it to be portable, then you'd just have to get implementations to optimize the idiom of a SUBSEQ on an adjustable array that never leaves scope and so can't be referenced anywhere else... just used to build up a simple-array
3:10:37
Josh_2
I have thousands of SLOC that rely on plists, and now I have to convert it all to use hash tables :facepalm:
4:33:23
Bike
i think the question is whether undefined behavior means the entire program is undefined, or just the particular form
4:34:36
beach
Let me modify what I just said then: Provided AREF is required to signal an error, I think you example is a violation of Common Lisp semantics.
4:35:44
Bike
but i was less asking about whether this would be conforming and more with whether people would like or dislike it or what if that was how it worked
4:36:24
beach
You are opening a Pandora's box here. Now, Common Lisp implementations can do what implementations of C do, namely exploit all undefined behavior to improve performance at all cost. :)
4:37:09
beach
Ah, yes, I understand. Well, my opinion would be that the definition of AREF should be fixed, so...
4:37:35
Bike
i recently spent like two entire days chasing down bugs caused by c compilers doing that, so i have no desire to continue that into lisp
4:39:09
Bike
i mean, let me put this another way. should WSCL or whatever else require type errors to be signaled by the operator, or could it just say that an error is signaled somewhere? for example, at any point after the violation is inevitable.
4:40:23
Bike
in any case i'd like the situation clarified, since as far as i can tell CLHS is ambiguous here
4:40:59
beach
rotateq: As Bike pointed out, simple arrays can very well have fill pointers and such.
4:41:37
rotateq
Oh okay, I wasn't too sure, so it was good again we talked about it. I just tried then a simple example in SBCL.
4:42:00
Bike
any phrasing would probably be pretty involved, but i think that's sort of required. the standard is kind of... vague in this area
4:42:05
rotateq
beach: All C implementations? I read some time Symbolics had their own too as with Ada and Fortran. :)
4:42:26
Bike
there's a distinction made between "unspecified" versus "undefined" consequences, and the distinction is that unspecified consequences are "harmless"
4:44:39
beach
Bike: It looks to me like we (collectively) now have the ability to improve on the standard. Exciting!
4:46:56
rotateq
beach: As I often see, even more things to learn about what others so easily call just "trivial" and that's way more worth to explore and deepen as just flying in too abstract and "modern" things.
4:47:29
Bike
is it? i mean, i can imagine it being so, but on the other hand, maybe if the error is signaled earlier the program is stopped before it can get halfway through a state change
4:47:55
moon-child
the program is probably already halfway through a state change when it figures out the thing that it's going to index later is not an array
4:48:19
moon-child
realistically, you are not going to recover state from a program which fails a bounds-check
4:50:53
moon-child
I don't know. But I can imagine cases where it would matter, esp. in context of other transformations
4:52:10
Bike
the other reason i'm thinking about this is that in a few cases, it is outright impossible to signal an error at the violation point
4:53:13
Bike
if you have (let ((f (the (function * float) f))) ...), there's no way (in general, but practically speaking, pretty much at all) for the implementation to determine f will return a non-float until it actually does
4:54:11
Bike
strictly speaking with the way function types are defined, it could technically work out, but nonetheless the error would be some time after the THE is evaluated
4:59:28
Bike
oh, and i forgot there is an analogous situation where the clhs does sort of say something
5:00:07
Bike
in 3.5.1.1.1, it says that when an error is signaled for a call problem (too many arguments etc), "it might be signaled at compile time or at run time, and if signaled at run time, it might be prior to, during, or after executing the call"
5:07:27
Bike
anyway mostly i want to sound out if someone has some code that this behavior would ruin, that kind of thing. and i'm just fishing for thoughts.
5:26:16
pillton
The (function * float) example is a good one. I think AREF should signal an error though. I think there should be another operator or operators introduced which either avoid using AREF or ensure that every call to AREF does not require checking its arguments.
5:28:58
beach
I was just wondering what the advantage would be to signal the error early. I can imagine that there would be performance advantages. However, nothing prevents an implementation from detecting the error early, but not signaling it immediately. Instead, it would have two branches, one of which evaluates the intermediate forms and then signals an error.
5:34:43
beach
Does that make sense? I mean, we would then have the performance advantage in that the normal branch could be optimized to assume the right type, but we would still respect a more strict definition of semantics.
5:40:29
beach
More generally I think. I am contemplating a way to maintain the possible performance advantages with an early detection while still respecting the semantics of individual operators doing the signaling.
5:40:31
beach
So (let ((a (foo))) (map nil #'print a) (aref a 0)) would turn into (let ((a (foo))) (if (arrayp a) (progn (map nil #'print a) (aref a 0)) (progn (map nil #'print a) (error 'type-error...))))
5:42:00
beach
In the "normal" branch, the call to MAP could then be optimized to sasume A is an array.
5:42:43
beach
But the MAP operation would be performed in both branches, thereby respecting the semantics that AREF has to do the type check.
5:43:54
pillton
I mostly worry about checking that the index is valid, which you still need to do in your example.
6:07:00
moon-child
beach: (let (a) (if cond (setf a definitely-an-array) (setf a who-knows-what)) (aref a 0))
6:08:27
moon-child
in that case, hm, you could hoist the check without any observable change in behaviour
6:08:49
moon-child
(if cond (setf a definitely-an-array) (progn (setf a who-knows-what) (check-type)))
6:09:00
ns12
Hello. If I have a string stored in a file, and I want to use that string as a string literal in Common Lisp code, I could use the hash-dot `#.` reader macro to read the string from the file. If I produce an executable of this program, the user will not need to have the file present because the file is only read at "read-time". My question is: how
6:10:57
moon-child
(however given more complex control flow such a simplification would no longer be feasible)
6:12:19
rotateq
and when you have a string with "foo" in this .lisp it is read directly as an object of class simple-string
6:14:02
ns12
From my understanding, the three phases are: read-time, compile-time, and run-time. During run-time, I can have read-time and compile-time by using COMPILE and EVAL. During compile time, there will always be a read-time phase. But where is the run-time? During read-time, where is the compile-time and run-time?
6:17:21
rotateq
or when using the #+sbcl(+ 1 2) it first looks if :SBCL is in *features* at readtime but if not gives back (values) directly
6:20:12
White_Flame
ns12: the phases really only have to do with compilation itself. It all happens "at runtime" and whatever is in the image at that time is available to any code at any phase
6:20:42
White_Flame
EVAL, however, does not invoke the reader. It starts from already-read source code
6:21:25
ns12
I think I need to study the HyperSpec. What is the relevant chapter? Is the chapter 3 "Evaluation and Compilation"?
6:22:22
White_Flame
the reader converts "(+ foo #.(+ 2 3))" to the list form (cl:+ cl-user:foo 5), assuming *PACKAGE is cl-user
6:22:46
White_Flame
the compiler then takes that plain list of symbols etc and converts it to another executable form
6:24:33
White_Flame
so when the reader is doing its thing, the current package matters, and it has to evaluate #. forms before any compilation of what it's working with has a chance to be compiled (because the compiler needs the reader to finish)
6:26:40
White_Flame
because the reader has to read that entire PROGN form before executing it, and the etc: package doesn't exist yet, meaning etc:init will fail the _read_ step
6:27:07
ns12
I see. The reader is a parser that converts strings to Lisp lists. The reader is programmable using reader macros. The reader will evaluate #. forms.
6:27:17
White_Flame
the actual creation of the symbol in the source code list (etc:init) fails, because that package doesn't exist at that time
6:27:41
White_Flame
and the reader is written in lisp itself, and all is executing in the same image :)
6:29:00
White_Flame
once these notions start being more known, the spec becomes much easier to read. It's not a tutorial at all
6:30:08
White_Flame
ns12: and once the reader is done, pretty much none of the rest of the system ever knows or cares about the original string representation. It's all about forms (which is what macros deal with, too)
6:30:49
rotateq
yes ns12, as it calls functions when defined readmacros are seen. the readtable works as a lookup-table
6:32:36
White_Flame
so for instance in your .asd file, any file that has been loaded before the current one should have all its macros, functions, toplevel vars, etc available
6:33:41
White_Flame
the real muckety muck is loading from .fasl, though. If you have purely read/compile time effects that leave things set, those won't necessarily reappear next time you load your project
6:33:46
ns12
What if the user-defined function is in the same file as the #. form that calls the function? I think EVAL-WHEN is needed, no?
6:34:38
White_Flame
because of stuff like (in-package), some forms have to be read one at a time, because they affect how the next one is read
6:34:51
rotateq
so better doing such things in files that are processed before, as with pushing keywords to *features*
6:42:13
ns12
White_Flame: "... the etc: package doesn't exist yet, meaning etc:init will fail the _read_ step" - Is this because the reader will try to intern `init` in the symbol table of the `etc` package, but that symbol table doesn't exist yet?