freenode/#lisp - IRC Chatlog
Search
5:46:00
oni-on-ion
not that i amn't anymores; but i think something like RLE could allow them optional. ie escape codes
5:53:26
no-defun-allowed
and now apparently there's an error about an unbound variable that is nowhere in my code
6:24:19
fiddlerwoaroof
pillton: yeah, the problem with those variables is that I only remember that I need them after I've tried to print a huge data structure
6:28:27
fiddlerwoaroof
I like the 4-byte encoding of unicode because it makes it easy to calculate the position of an arbitrary code-point.
6:29:48
fiddlerwoaroof
It would be even better if there was an encoding that normalized every grapheme into a fixed number of bytes
6:34:18
fiddlerwoaroof
Hmm, I guess that's impossible because you can combine diacritics, etc. arbitrarily
6:47:09
no-defun-allowed
fiddlerwoaroof: i do not believe so, i have two auxiliary functions ENSURE-SYMBOL and ENSURE-STRING which handle strings and symbols in the macro body so i can write somewhat neater definitions for a macro
6:47:14
no-defun-allowed
eg when i write segments, ((foo key-value)) goes in, (("foo" :key-value)) comes out
7:28:20
no-defun-allowed
aeth: i don't like the "use debugger hooks to kill lisp" report method very much, do you?
7:45:30
splittist
Did someone point elderK to https://www.hexstreamsoft.com/articles/common-lisp-format-reference/ ?
8:00:46
splittist
elderK: this, from PCL, is often handy, too http://www.gigamonkeys.com/book/a-few-format-recipes.html
8:10:37
jackdaniel
you may want to read discussion after you got to sleep, makomo has presented different expectations from said macros
8:11:04
jackdaniel
as of ix.io, I have script in my ~/bin called ix, so I just call it like `ix foo.lisp` and get the url
8:15:51
jackdaniel
interesting historical paper about continuations: http://www.math.bas.bg/~bantchev/place/iswim/conti-disco.pdf
9:14:18
elderK
Is there a way I can set the default eval-when of a file, without having to wrap everything in the file in a giant eval-when form?
9:22:19
frodef
elderK: Wrap it (in some sense) around the form that loads that file into your system?
9:39:30
splittist
elderK: if everything in the file is being treated in the same way, shouldn't you be thinking about file-level compilation and loading, rather than form-level?
9:44:09
elderK
Like, I have a macro. And it makes use of a bunch of helper functions to do the expansion.
9:44:22
elderK
Now, from what I understand, the compiler will evaluate the macro - expand it - as it goes about its work.
9:44:46
elderK
It will compile the functions the macro relies on - but not be able to execute them - unless I have them in an eval-when :compile-toplevel, correcT?
9:50:45
splittist
This might help. (Or not.) https://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node68.html#SECTION00933000000000000000
9:54:06
splittist
It is common to put macro definitions in a different file which is loaded (or compiled and loaded...) before the files which use them. But I guess you know that.
9:58:23
elderK
splittist: Aye. I'm just... wondering about the functions that the macro uses to do its expansion.
9:58:33
elderK
Like, my macro doesn't do all the expansion itself - it calls out to a bunch of helpers.
10:00:56
splittist
elderK: if you decide you hate the whole thing you can read https://fare.livejournal.com/146698.html (:
10:09:59
ogamita
Of course. CLHS is not a tutorial, it's a reference specifciation. To avoid ambiguity, they strove to avoid any redundancy. There's no order (you need to read it entirely several time, and basically to retain everything in mind).
10:09:59
ogamita
On the other hand, CLtL2 doesn't describe the ANSI CL standard, but some preliminary version. So some explanations don't apply. If you can sort it out, it can be interesting.
10:34:16
elderK
So, if I have some (defun ....), and I'm compiling, is that form simply "compiled' or is it made available to the compiler for use?
10:35:43
dtornabene
just make sure to select the correct lisp room you're looking for, I missed that at first and searched clasp instead of lisp
10:36:15
ogamita
elderK: this is why you need to wrap them in eval-when (:compile-toplevel) when you want ot use those functions in macros.
10:36:36
elderK
ogamita: Okay, so, if a macro makes use of helper functions, does that mean that it cannot be correctly expanded at compile-time, unless those helper functions are eval-when'd to be included in the compile-time environment?
10:37:17
ogamita
Well, eval-when is one way, when the functions are defined in the same file as the macro in the same file where the macro is used.
10:37:50
ogamita
But it is enough that the functions be present in the compilation environment whatever the mean; for example, you can put them in a separate file and load them in the environment before compiling the files using the macro.
10:38:09
elderK
From my understanding so far, specifying both :compile-toplevel and :load-toplevel, at the top-level, and in "NCT" mode, switches us into "CTTM." In that mode, things are processed (compiled?) but also evaluated (made available to the compile-time environment?)
10:38:10
ogamita
Also good to have them in the environment before compiling the macro to avoid undefined function warnings.
10:38:58
ogamita
Now, :compile-toplevel is when you call compile-file. :load-toplevel is when you call load on the fasl. :exectue is when you call load on the source.
10:39:07
elderK
I get the feeling this is going to be one of those things I'm going to have to quiz myself daily on for awhile :)
10:40:03
ogamita
The no brainer is just to use (eval-when (:compile-toplevel :load-toplevel :execute) (defun foo (…) …)) (defmacro moo (…) (foo …))
10:40:26
ogamita
The thing is that if foo is not used at run-time, then you could skip :load-toplevel and :execute.
10:40:46
elderK
Things get more complicated though when we're nesting, though, right? Like, If we have a top-level eval-when with (:compile-toplevel :load-toplevel), that switches us into CTTM and processes its body. If that body has as an eval-when of :load-top-level and :execute, it'll be processed / evaluated in the CTTM?
10:41:30
ogamita
For example, you could have a very big translator from some language to lisp, load it in the compilation environment and use it thru a macro to translate the source, but you wouldn't need it at run-time.
10:42:09
elderK
Okay, that makes sense. I was wondering if I'd need the full (:compile-toplevel :load-toplevel :execute) or not.
10:42:25
ogamita
elderK: yes. The only case normal human brains can understand, is when eval-when is toplevel. Embedded and not-toplevel needs mutant brain powers.
10:42:28
elderK
The idea is, the macro will be made available for people to use at the REPL or normally.
10:43:35
elderK
Would that mean that the helpers and stuff that help generate the expansion, be needed at runtime?
10:44:04
ogamita
I've got two functions: (quick-install-all) (quick-load-all) ; makes a half GB image ;-)
10:45:07
elderK
Okay, after all this, I feel that this is broken: https://github.com/mgi/binary-io/blob/master/binary-data.lisp
10:45:22
ogamita
you could call the repl at compilation-time, at macro-expansion-time or at read-time too;
10:45:47
elderK
ogamita: Right, and if you called hte REPL at compile time, you'd be in the CT environment, right?
10:46:09
elderK
Macro-expansion could happen at compile-time, or at "normal REPL time", which I consider the same as read time?
10:46:57
elderK
Thank you for helping me, btw. I imagine this is very obvious for anyone with experience :)
10:47:37
ogamita
No, don't confuse times. The REPL = READ EVAL PRINT LOOP, so there's a read time in the repl. Then there's EVAL. EVAL can be implemented as (funcall (compile nil `(lambda () ,expr))) so there's a compilation-time and a run-time. The compilation time must at minmium, expand the macros. So there's a macroexpansion time embedded there.
10:47:51
elderK
:P Moment, you're overloading my brain. So, if you call compile whatever, the environment you're in at the tmie that call is made, is hte "compiletime environment"?
10:48:24
ogamita
The compilation environment is forked (or the same) from the startup environment which is the runtime environment for the REPL.
10:48:32
hajovonta
I think these "times" make more sense when you think of the life cycle of a compiled functions
10:49:12
ogamita
elderK: good question. I have a doubt about COMPILE. It would definitely be ac ompilation environment for COMPILE-FILE. We'd have to check for COMPILE.
10:49:17
elderK
ogamita: So, if I start the REPL and do a bunch of stuff in that REPL, then use compile, the compile-time environment will be the same as the REPL at the start, ignoring all the stuff I've done in the REPL since?
10:50:00
elderK
As for the file I linked, I also find it weird that the macro is defined before its helpers.
10:50:03
ogamita
no, "startup environment" refers to the environment where the compilation starts. Not the initial environment.
10:51:40
elderK
What I'm trying to say, is that we start the REPL. We do a bunch of stuff, then say "compile". The compiler will use the current environment as the compile-time environment. I.e. It will be aware of all the stuff we've done.
10:51:54
ogamita
elderK: it can be a copy of the REPL environment, or it can be the REPL environment.
10:52:19
ogamita
It could also be not the REPL environment, eg. if you invoke compile-file in a batch command.
10:52:53
elderK
ogamita: Well, yup. That makes sense. If it were a batch command, it'd use the "Default" environment, right?
10:53:25
elderK
I imagine you could for instance, say "I want you to compile these files, batch style, using this image."
10:53:27
aeth
no-defun-allowed: I've actually never had tests fail remotely because I always restart SLIME (to avoid stale image state, e.g. calling a function that has been renamed) and then run tests before pushing. I guess it would be possible if the remote tester runs several implementations.
10:53:45
ogamita
The problem is that COMPILE only compiles lambda expressions, not toplevel forms. Only COMPILE-FILE knows how to compile toplevel forms. So when you use COMPILE, you cannot have toplevel eval-when forms…
10:54:35
elderK
Okay, then I /definitely/ think https://github.com/mgi/binary-io/blob/master/binary-data.lisp is broken in some way.
10:54:43
ogamita
so (compile nil '(lambda () (eval-when (:compile-toplevel) (print :compile-toplevel)) (eval-when (:load-toplevel) (print :load-toplevel)) (eval-when (:execute) (print :execute)) 42)) doesn't print anything, and (funcall *) prints :execute.
10:55:21
elderK
Right, compile-toplevel and load-toplevel don't trigger because it's not toplevel, right?
10:55:59
no-defun-allowed
That's fair, aeth. However it appears that without disabling the debugger, fiveam quits and the results aren't entirely printed.
10:56:25
no-defun-allowed
On my machine doing sbcl --load tests.lisp it just cuts out, but on CI it runs the whole way through.
10:56:57
elderK
ogamita: So, if my macro is attaching a bunch of methods to some generics, does that mean the defgenerics themselves need to be compile-toplevel / load-toplevel?
10:57:06
no-defun-allowed
That kind of behaviour annoyed me, so I just check the return value of fiveam:run! and use an appropriate error code if the value is NIL.
10:57:58
ogamita
elderK: for this kind of question, you have to look up whether the defining operator has compilation-time or run-time effects.
10:58:26
ogamita
for example, defun doesn't define the function in the compilation environment, it only takes note that the symbol names a function.
10:58:46
aeth
no-defun-allowed: So you have to manually return the error code to get the CI to report the correct result? Not surprised, but never encountered it either way yet afaik.
10:59:08
ogamita
"defgeneric is not required to perform any compile-time side effects. In particular, the methods are not installed for invocation duringcompilation. "
10:59:23
ogamita
So if you want to add methods at compilation time from your macro, you need an eval-when.
10:59:43
ogamita
But if your macro _expands_ to the adding of methods, this will occur at run-time, so no eval-when is needed.
11:00:27
elderK
So, out of curiosity, if toplevel stuff only really pays attention to :compile-toplevel and :load-toplevel, why do I need to specify all three situations?
11:01:14
ogamita
the :execute is for when you load the source. In that case, in general you want the same as (or :compile-toplevel :load-toplevel).
11:01:22
elderK
ogamita: In that example, does the #. happen at the time hte macro is read, or at the time it's expansion is?
11:01:24
no-defun-allowed
aeth: Yes, my current script replaces the debugger hook with a call like (UIOP:QUIT -1) and GitLab picks up on it.
11:01:49
no-defun-allowed
The shiny new one on my desktop quits after all the tests are run and doesn't rebind any debugger stuff.
11:01:59
ogamita
If your source is not designed to be used at the REPL, but eg. to save an executable image, then you could skip the :load-toplevel :execute situations if your functions are only used to compile it.
11:02:35
ogamita
elderK: which is either load (:execute) time, or compile-file (:compile-toplevel) time.
11:03:09
elderK
So, what exactly is :load-toplevel for? If :compile-toplevel is compile-file time, and :executive is "load the source" time.
11:03:10
no-defun-allowed
The shiny new one also comes with a fairly straightforward fuzz tester, which I used to find that cl-base64 bug.
11:06:21
ogamita
elderK: for example you can compile on one machine, load the fasl on another, save an executable image, and run the program on a third machine.
11:07:31
ogamita
#P"…" builds the pathname at read-time. (pathname "…") builds it at run-time (when evaluated). Some paths are known at compilation-time, some when you "link", when you load the fast to save the image, and some other paths are only known at run-time, when the user launches the program.
11:08:07
ogamita
So you must be careful with when the paths are used. Developers often coalesce all these situations, so there's often some confusion here.
11:08:18
elderK
Make a few files, have eval-whens, load the source, compilet he source, etc. See if I can learn.
11:36:26
elderK
Say, I'm separating things into their own packages, for namespacing reasons. But then, I have a "unification" package, which brings in and exports just the stuff I want people to use?
11:41:05
beach
elderK: You have one package that contains symbols that you want to be visible by client code. It contains only those symbols. No code is written with an IN-PACKAGE of that package.
11:42:27
beach
elderK: Then you have several "implementation packages". You may have one or more files that start with (IN-PACKAGE ...) of one of those implementation packages.
11:42:52
beach
In such a file, you do (defun main-package:function1 ...) (defclass main-package:class1 ..) etc.
11:44:28
beach
elderK: It works, because packages contain only symbols. They are not modules so they don't contain code or definitions.
11:46:49
elderK
beach: I see. So, I have one "proper package", and a bunch of internal packages. Those internal packages do not need to have a defpackage form?
11:47:40
beach
And you can have as many as you like. Client code will only see symbols in the main package.
11:48:31
beach
I often put each "implementation module" in its own directory. Then I have a separate package.lisp file for each such module, in its directory.
11:49:00
beach
One of my "modules" typical consists of a directory, a package.lisp file, and an ASDF system definition.
11:49:08
elderK
Okay, so, I have my various packages. I have one "main" package which is to be used by people. All my internal stuff is in the internal packages, and for the things in those "internal" packages, where they define something that is meant to be in the public interface, they just define it straight into that pacage?
11:49:18
beach
That way, I can have alternative implementation for the same functionality if that's what I want.
11:50:13
elderK
This might be overkill for what I'm doing. I just want to make sure the names I've used for helpers, for one set of macros, doesn't conflict with the helpers for another macro.
11:50:45
beach
More precisely, code in one of the implementation modules uses the main package as a package prefix directly for defining functionality that is to be seen by client code.
11:51:25
elderK
So, why is this method preferred over the one where you import and rexport from the internal packags?
11:52:40
beach
The structure is also simpler than if you have to import and re-export every symbol explicitly.
11:53:17
beach
And client code can be sure that the main package contains only visible symbols, in case it wants to iterate over all symbols avaliable to it.
11:53:30
elderK
So, what if one of my implementation packages wants to add some new symbols to the main package, but also use some symbols from the main package?
11:54:39
beach
And I just explained how implementation modules use the symbols from the main package, namely by using a package prefix.
11:55:08
beach
That way, it is much more obvious to someone reading the code for the implementation module what symbols come from the main package.
11:55:35
beach
Plus, you can use symbols with the same name in the implementation package as the corresponding symbol in the main package without any clashes.
11:56:14
ogamita
The current style of development, where the code is stored in files that are loaded and compiled separately by a system definition system (asdf), asks for a more static declaration of some elements such as the packages.
11:57:15
ogamita
Note that this prevents circular dependencies between packages (this is good software engineering practice!). But lisp allows circular dependencies between packages, established at run-time. You can find them in legacy code, but don't do it yourself.
12:15:29
jmercouris
elderK: well, in this case it is a function that given a string, and a list of strings, will return a list of strings that fuzzily match
12:16:37
jmercouris
in other words, there is not a strict convention as there is with something like predicates
12:18:34
jmercouris
I think I might do something like that though, with -fn at the end suffixed, I like it
12:22:16
ogamita
I would use fuzzy-matcher or just fuzzy-match. I'd decide on the name depending on usage. (funcall (fuzzy-match foo) bar)
12:22:38
elderK
I'm trying to apply what beach explained earlier. But now, because of specifying the package name, lines are way longer.
12:24:14
elderK
What happens if a package A says it exports symbols S1, S2. And package B uses package A, and contains a definition for those S1, S2. Do those definitions wind up being the definitions for A's S1, S2?
12:25:02
elderK
Or do those definitions for S1, S2 in B shadow those from A? (Those symbols have no definition in A, though.)
12:26:21
Bike
if you have like, a:s1, and *package* is B, and B uses A, and you read "s1" by itself, that will be a:s1
12:26:25
elderK
:( Sorry, I'm using bad terminology. The packages contain the symbols, right? That's all. But somehow, you associate a binding for that symbol, no?
12:27:53
elderK
Okay, so if I have a package B that uses package A, which contains the symbol S1, and I (defun S1 ...) in package B, is that function bound to the symbol S1. So, if someone later uses Package A, and calls S1, it uses the function that was defined with that name from B?
12:28:45
Bike
Try it: (defpackage #:foo (:export #:s1)) (defpackage #:bar (:use #:foo)) (let ((*package* (find-package "BAR"))) (read-from-string "S1"))
12:30:37
Bike
this happens way before anything like defun is compiled or evaluated. it's just how the code is parsed.
12:31:07
ogamita
(defpackage "INTERFACE" (:use) (:export "S1" "S2")) (defpackage "IMPLEMENTATION" (:use "CL" "INTERFACE")) (in-package "IMPLEMENTATION") (defun s1 () 1) (defun s2 () 2) (defpackage "CLIENT" (:use "INTERFACE")) (in-package "CLIENT") (cl:list (s1) (s2)) #| --> (1 2) |#
12:32:50
splittist
elderK: some people like this explanation (warning: pdf) http://www.flownet.com/gat/packages.pdf
12:35:18
ogamita
another explanation is an implementation of the package system: https://github.com/informatimago/lisp/tree/master/common-lisp/lisp-reader
12:37:09
ogamita
elderK: otherwise, the trick is to read the operators. defpackage defpackage in-package defun defun defpackage in-package.
12:50:14
p_l
I think stuff that has literal CL:ASSERT isn't compiled out, but implicit asserts (like type declarations) can be optimized out
12:53:17
jcowan
elderK: It could all be much worse: you could be trying to wrap your head around the R6RS notion of explicit phasing, with its doubly infinite tower of (in effect) eval-when situations: normal code, macros, functions used by macros, macros in the last, functions used by the last, and so on forever. Then there are negative phases, which I can only understand for brief periods before forgetting again
12:53:52
jcowan
fortunately, only one Scheme is left standing that implements this, and it will be phased out before 1.0
12:54:42
ogamita
elderK: you could use a feature: #-with-heavy-assert (assert (2-hours-compute-predicate-p foo))
12:55:20
ogamita
elderK: so you cah (push :without-heavy-assert *features*) and reread/recompile to remove the assert.
13:30:16
jcowan
From the Vax Lisp (it's a CL) manual: "You can recover an input expression or an output value by using the following 10 unique variables: / // /// * ** *** + ++ +++". Something a bit wrong here?
13:39:48
jcowan
I don't think base 8 made it off the PDP-10 except in the rudimentary form of *input-base*.
14:18:16
Xach
sometimes i have a function that is really just a thin wrapper over gethash, for example, but i'd like to hide the extra return value
14:19:08
elderK
Well, if my function is meant to return a single value, well. I'd like that to be the case :)
14:44:27
dim
The standard has it that “values is the standard idiom for indicating that only one value is to be returned”
14:50:45
ggole
(values (values 1 2)) is an interesting snippet - the same operator doing quite different jobs
14:54:22
Xach
Inline: forms don't expand into multiple forms, but they may evaluate to multiple values.
15:23:49
jackdaniel
this is fun to read: https://bugs.launchpad.net/calibre/+bug/1714107 (some folks trying to convince calibre maintainers to migrate from python2 to python3, because the former is "retiring") [sorry for the offtopic, otoh it proves, that having standard is a nice quality]
15:29:27
Xach
I think there's sometimes a simplistic view of what motivates other people to change their code for you
15:30:08
beach
This is precisely what I am talking about when I give talks to industry, urging them to use standardized languages.
15:30:19
Xach
"change this to make it conform to the standard" does not always motivate someone to make a change.
15:31:02
Xach
common lisp adherence to standards (in a thorough way) has not always been very good, and it saw a surge of improvement over the last 10 or so years
15:31:43
Xach
but if you rely on something standard, but your platform does not implement the standard, you cannot always rely on "change to fit the standard" to save you, without other agreements
15:36:11
fade
the incompatibility between python 2 -> 3 was what lead me to finally use CL in anger.
15:36:30
fade
"If it's going to be a different language anyway, I may as well use one that is both fast and stable."
15:38:07
ogamita
popularity leads to legacy, legacy leads to bit rot, bit rod leads to the dark side.
15:38:40
fade
the 2 -> 3 migration has been the biggest fuckup in a language ecosystem since I've been watching such things, a period dating back to the mid 1980's.
15:39:33
fade
I've often thought that it should result in a lot of new developers for lisp, but I haven't run into too many.
15:41:59
sjl_
Porting a large Python 2 codebase to Python 3 would be painful, but much less effort than learning CL and porting it to CL. That's one possible reason.
15:43:12
pfdietz
Xach: widespread non-compliance with the standard motivated me 15 years ago or so to write ansi-tests.
15:43:33
nixfreak
hello how can I get started to created a "HOT" folder , meaning certain files get copied to a file and a script gets executed to push those files somewhere else
15:44:02
Fade
sjl -- that's true, but once you've loaded lisp into your head, you've solved all of the problems associated with the python ecosystem permanently, if only locally.
15:45:22
sjl_
Fade: sure, but the first part of that (learning Lisp) is non-trivial, and the urge to "Fix the problem and move on with my life instead of learning new tools" is often strong.
15:45:37
Fade
lisp can open and append files, and with the right extension, open a socket and move data through it.
15:46:42
minion
nixfreak: look at pcl: pcl-book: "Practical Common Lisp", an introduction to Common Lisp by Peter Seibel, available at http://www.gigamonkeys.com/book/ and in dead-tree form from Apress (as of 11 April 2005).
15:46:49
fortitude
has anybody used cffi-grovel:process-grovel-file in a while? seems to be an issue with its use of uiop:ensure-pathname, but the last relevant change was from 2015
15:46:56
sjl_
I mean, I agree with you -- Python 3 and Clojure 1.3 were a big influence on me choosing a stable language like CL. But I can understand the decision to suffer through an update rather than go through a full rewrite.
17:13:45
beach
That reminds me of a student I had in the past who wrote is C code with single letter variables only. When I asked him why, he said so that the program would execute faster.
17:16:05
sjl_
uLisp is fun if you do Arduino-based stuff. I've used it for a couple things. I even hacked in floating point support, and the author eventually merged it into the main repo.
17:17:40
copec
I have a smartos box doing all the things, and I actually just want to do rpc with them
17:18:23
sjl_
The homepage says > platforms with more than 2 Kbytes of RAM arbitrary user-defined symbol names are supported.
17:19:48
copec
I want the actual control to be in a zone on the smartos box with the devices just acting as control bridges
17:23:08
didi
I can't get over the fact FORMAT doesn't have a directive to print conses. It bothers me when I want to print alists.
17:24:12
copec
although, having my kids directly program some micro controller projects with this ulisp would be fun
17:26:03
Bike
i guess you could map the alist to have actual lists beforehand, or use ~//, but it's not quite as smooth
17:26:12
anamorphic
copec: I used mqt for rpc previously with esp8266s. I would like to try it again with ulisp
17:32:59
copec
The 'protocol for updating using semantics that follow from CL would suite it wonderfully, I think.
17:43:35
copec
That thought just came to me thinking about these micro controller system images being all lisp, something something nasa doing incremental upgrades through space via lisp, and how cloud app deployment is going towards orchestration (config management) states to deploy applications