freenode/lisp - IRC Chatlog
Search
17:30:02
jcowan
s there any trick to load a system such that the current package is changed after the system is loaded? This would be useful when implementing a different language in CL.
17:30:57
jcowan
For example, suppose I write an implementation of Elisp in CL. I define two packages, ELISP (which inherits from CL as usual) and ELISP-USER (which inherits only from ELISP). Then I want to load this and have the user wind up in ELISP-USER, but I don't see any way to do that.
17:37:07
jcowan
Well, if the user has to type that at the REPL, it's rather verbose. And if you put it in a file for convenience, it doesn't work. Indeed, at the REPL you might just as well write the two forms separately without progn.
17:43:11
jcowan
In what package does the elisp symbol live? Presumably CL-USER. Is that acceptable practice?
17:44:06
jcowan
So again the user has to type two forms: a load and (elisp). This is some improvement on find-package or in-package, but not optimal.
17:49:40
jcowan
or if not put in CL-USER, the user must type (load ...) and (elisp:elisp). Uglier yet.
18:15:29
pjb
jcowan: note that even if you put elisp in cl-user, the user may change the current package before wanting to call elisp, so he cannot type (elisp) willy nilly.
18:15:55
pjb
jcowan: some repl let you define commands that are accessible whatever the current package. You could define such repl command to start elisp.
18:25:06
jcowan
So if use-package (or its defpackage equivalent) is discouraged because name pollution, which is recommended, importing or qualified symbols?
18:27:24
pjb
And neither is use-package really. See for example: https://github.com/informatimago/rc/blob/master/common.lisp#L437
18:28:51
pjb
But indeed, there may be some name collision, hence the carefully currated package list https://github.com/informatimago/rc/blob/master/common.lisp#L302
18:30:01
pjb
jcowan: the point is that the owner of the package gets to decide on the used packages.
18:37:38
jcowan
Yes, however, you take the risk of breaking your code if the used package is updated.
18:39:03
jcowan
If/when I implement ISLisp I am going to add defpackage, in-package, and single-colon qualified symbols to the language definition. The ISLisp notes say that there was an intent to add modularity, but they ran out of time.
18:42:48
pjb
jcowan: even if you don't use the package, if there's an update, there's potential bitrot.
18:42:50
jcowan
There is going to be a fair amount of shadowing of CL required because of slightly different semantics: e.g. internal-time-units-per-second is a function, and you can't define it as such without shadowing it
18:45:37
fiddlerwoaroof
Yeah, I don't know that there's a consensus about avoiding :USE, but I generally prefer to qualify my symbols so I know where they come from
18:46:08
fiddlerwoaroof
This is a bit painful in CL because there's no standard way to locally rename a package.
18:46:26
jcowan
People make a big deal about distinguishing "bug fixes" from "breaking changes", but every bug fix *is* a breaking change if your users have already worked around your bugs.
18:47:11
fiddlerwoaroof
some libraries provide something like that: https://github.com/3b/package-local-nicknames
18:47:35
fiddlerwoaroof
Having an extensible reader is something I miss when I write Clojure or Elisp
18:50:06
fiddlerwoaroof
I remember one that used a reader macro to resolve the nicknames in a conforming manner
18:51:12
jcowan
The file https://github.com/3b/package-local-nicknames/blob/master/package-local-nicknames.lisp puzzles me: if loaded, it does nothing, because it consists of a single in-package form. What's it meant for?
18:56:37
fiddlerwoaroof
And then there are things that use ASDF to manipulate the environment a system's source files are loaded in: http://quickdocs.org/package-renaming/
19:01:07
void_pointer
I am trying to make a window, do some stuff on the main thread, and then close it without user input (if anyone is curious, this program is querying the rendering capabilities and doing some tests before closing).
19:01:54
void_pointer
But I am not sure how to get something running on the main thread after I create it.
19:09:02
pjb
void_pointer: you cannot do it with bordeaux-threads, but there are implementation specific ways to run stuff on the main thread.
19:09:32
pjb
void_pointer: you can also portably implement your own loop running on the main thread, waiting for messages from the other threads to be evaluated.
19:11:02
void_pointer
pjb: I would like to avoid implementation specific stuff if I can help it but if it is the only choice then that is the way it is
19:13:57
fiddlerwoaroof
Anyways, for the specific purpose of running something in the main thread, this works well: https://github.com/Shinmera/trivial-main-thread
20:15:46
jmercouris
this isn't exactly a Lisp question, but a question about how you would use a library
20:16:04
jmercouris
so let's say you are using drakma to get the body of a page, what process, would you use to strip any ads from the page?
20:16:30
jmercouris
I guess it isn't as simple as just removing JS blocks on the page, as those can be dynamically inserted
20:17:20
jmercouris
I am thinking somehow you would need to be able to capture all network requests and determine if they are from a domain that serves Ads or not using a list, and then deny requests to load assets from domains on that lis
20:36:41
jmercouris
pjb: Well, it is a web-page so the content type would be something like text/html, right, but drakma will just load the body, you would need to traverse the resources to determine whether to load those
20:37:03
jmercouris
I'm debating whether I want to do the adblocking on common lisp still, or just use the built in webkit content blocking API (which will probably be way way faster)
20:40:18
pjb
jmercouris: so once you know it's html, you can read the standard about the html format, and parse it and find the ads in there.
20:40:38
pjb
there are also html and xml parsers, but I'm not sure how complete and uptodate they are.
20:41:18
jmercouris
pjb: most ads these days are served via ajax queries, so it's not as simple as just removing the offending html
20:41:55
jmercouris
sometimes there are place holder divs or something, that get populated with ads, maybe if you remove the placeholder div, then the ad won't even load
20:42:26
jmercouris
maybe it would be best to implement an AI, train a model and distribute that model
20:54:07
pjb
jmercouris: well, if you want future proof, shot all the guys on the w3c. They keep issuing new standards! You will have to catch up.
20:57:25
anamorphic
Hi, I defined a define-setf-expander here https://paste.ofcode.org/ygctgJ6i8KCnDFHgJiuhvG Basically my first attempt at an exapander. Does it seem correct? Checked it for things like double evals. Not sure how else I could have messed up though...
21:08:50
jmercouris
so I can use something like (cl-string-match:match-re ".*a.*b" to do a fuzzy search for anything with a and b in a row, but how could I make that case insensitive?
21:20:44
aeth
in regex it's just (afaik) [Aa] or [Bb] anyway and is only hard when you want to extend it past that
21:21:20
jmercouris
aeth: yes, but would not be quicker to transform my strings to all lowercase instead off branching on every single check?
21:24:51
jmercouris
then again, using match-re is way more expressive than having a remove-if predicate that has a cl-ppcre regex wrapped within a lambda
21:25:39
jmercouris
you know, I'm not carving things into a stone tablet here, I think I will go with lowercasing for now
21:26:14
aeth
Usually I just write my own state machines and either parse character-by-character or substrings in a line-as-string, using only things like string=, char=, etc.
21:26:43
jmercouris
aeth: so what, you generate automata for every type of match you wish to do and store these models?
21:27:20
aeth
Well, no, I do it manually because I have to do it often enough to find the pattern for the DSL, and I haven't done it often enough. Just turns 1 line into 30, though.
21:28:19
jmercouris
interesting, I'm not doing the parsing for a DSL, just fuzzy matching user input against a list of candidate
21:29:04
jmercouris
though I could do something like that, I think I'll stick with the single line for now :P
21:34:16
aeth
jmercouris: I think you could do this, though, assuming you split it into lines or have the :start and :end points and it's in a string (not a stream): (find-if (lambda (c) (or (char-equal #\a c) (char-equal #\b c))) "abc")
21:35:21
aeth
(position-if if you want to get the position and then look for whitespace separators to get the word that contains that character)
21:36:38
aeth
(if you want more than one match, that's where it gets tricky because you'd have to repeatedly run position-if with modified starting points)
21:40:08
makomo
aeth: were these emebedded DSLs (within CL)? what did you need string matching for in that case? looking for symbols with special patterns in their names or something?
21:40:42
aeth
makomo: My most recent work in string matching was for parsing https://www.chessprogramming.org/UCI
21:42:46
aeth
makomo: Well, my plan is to eventually handle it in a macro just like anything else (XML, JSON, HTML, etc.)
21:47:20
aeth
makomo: (:isready) wouldn't require string matching. Seeing if the other side sent the response "readyok" would require string matching.
21:49:10
jmercouris
however, if you have 3 letters that you want to fuzzy match in a row, it will not work
21:52:19
makomo
aeth: i didn't pay close attention to the page. now i see that it's a protocol. i guess that's a DSL, but i was thinking in the "source code sense" (the usual sense) of the word
21:52:43
aeth
jmercouris: For a...b...c... you'd have to write three position/position-if tests, with each one informing the :start of the next
21:59:07
jmercouris
I'll stick with the single line solution, performance is not an issue, and people after me will also have to read the code, and I don't necessarly need them to be fluent in my automata design :D
22:01:14
aeth
The state machine DSL for writing the embedded DSL for handling someone else's external, string-based (and hopefully line-based) DSL
22:02:11
jmercouris
I wasn't being very specific, often times things are very clear in my head, its just that when the words come out, I forget that you aren't also in my head :D
22:02:51
jmercouris
so there are things I often think I've said or included, but on second reflection, I realize I omitted, it is on accident though
22:19:24
no-defun-allowed
mine is 10:00:00 since i like in gmt+10 but yes it should be midnight in UTC
22:19:35
aeth
for me: (multiple-value-list (decode-universal-time 0)) => (0 0 19 31 12 1899 6 NIL 5)
22:20:33
aeth
It should basically just be a reversal of ISO-8601's format until the time zone/DST/etc. stuff at the end.
22:21:23
jmercouris
I'm familiar with multiple-value-bind to extract multiple values returned by a form, but how can I write a defun that returns multiple values?
22:22:07
aeth
In fact, values probably uses values-list and the compiler probably optimizes values-list to not cons because of that.
22:23:54
aeth
jmercouris: If you're doing something in a loop, you have two options in CL: mutate an object or use multiple return values. There is no magic immutable list/tuple that will be optimized away.
22:24:55
aeth
I mean, multiple return values probably cons at some point, but almost certainly past 4 and possibly past 10-20
22:25:51
aeth
(values 'a 'b 'c 'd) will, in any reasonable implementation, not cons, so it is effectively free (this has come up before and technically every function call pays a slight price because of this, but... it's already paid whether you use it or not so that makes it "free")
22:26:43
aeth
makomo: The line where it becomes inefficient is certainly after 4 in a reasonable implementation
22:27:52
aeth
jmercouris: There's also a really neat parallel between a defsetf that can take in multiple values and a function that returns multiple values. Composes very nicely imo.
22:28:17
makomo
hm, reading that sentence a couple more times made it have more sense. guess it's a tricky formulation (for me at least)
22:29:51
aeth
If your getter returns multiple values, your setter should use DEFSETF. If you're not writing multiple return value functions it's not surprising that you haven't needed it.
22:32:22
aeth
jmercouris: So those are the three uses I know of. (1) when one value's more important than the others (e.g. FLOOR), (2) when you don't want to cons but want to return multiple things (imo only really return lists when there's a structure, like building syntax in a macro or returning a plist/alist), and (3) when you want to combine it with a DEFSETF
22:33:58
jcowan
Consider subtypep, which returns two values: what it believes and whether it is ignorant.
22:37:10
aeth
gethash is another good example, where the second return value is present-p so you can tell if it's a NIL that was stored in the table or a NIL as the default default value (which you can override, btw)
22:46:54
jcowan
Scheme uses explicit continuations in that case, either just for failure or for failure and success, depending on the library.
22:47:14
jcowan
Lua just says "No nil as a key or value", though nil is not identified with any sort of empty container.
22:49:00
aeth
The thing about not using exceptions is that it's presumably cheaper to use hash-table as a duplicate-spotter.
22:53:42
aeth
easily one of the worst parts of the language's syntax, up there with trying to use lambda/FP
22:54:54
jmercouris
unless you wish to make your own exception type, in which case, the syntax and design leaves a lot to be desired
22:55:12
aeth
jmercouris: I strongly disagree about Python's syntax. For one, "1+1" is valid. That should be invalid in any language that values readability as its goal. "1 + 1" should be enforced by the language, not by convention.
22:55:27
aeth
Having space as a separator means you get kebab-case which is superior to underscore_case, too.
23:02:07
aeth
I'm not sure if that version of it has {1+1} as invalid but the logical way to handle that transformation is to treat it very similarly to an s-expression
23:08:49
LdBeth
ACTION uploaded an image: 屏幕快照 2018-11-18 下午3.08.29.png (749KB) < https://matrix.org/_matrix/media/v1/download/matrix.org/DNiFMBZoIMSHcridgBBaWVxK >
23:09:27
makomo
also https://www.cs.cmu.edu/afs/cs/project/ai-repository/ai/lang/lisp/code/syntax/infix/infix.cl
23:15:30
aeth
If you're porting software over, turning (x + y) / z into {{x + y} / z} is probably the best decision
23:16:05
aeth
The lack of popularity of an infix package means few people are porting things at the moment, which is bad
23:16:15
fiddlerwoaroof
ACTION the bigest mistake of infix languages is operator precedence, the second biggest mistake is mixed associativity
23:16:39
fiddlerwoaroof
If you're going to do infix, J/APL have it right: all one precedence, always right-associative.
23:18:25
aeth
fiddlerwoaroof: Last time I wrote infix I didn't support mixing. So (infix (x + y - z)) was invalid. You'd have to do (infix ((x + y) - z))
23:18:50
pjb
In practice, you'd just write the code to compute your spaceship position and propulsion in pure lisp anyways.
23:19:18
pjb
For example, if you implemented a GPS system, you could take the formula from the specifications and use an infix model to avoid having to translate them yourself.
23:23:09
fiddlerwoaroof
precedence is just confusion, especially once you expand beyond standard mathematical notation
23:25:06
fiddlerwoaroof
And, I'd argue that order of operations is a misfeature in mathematical notation that's been around long enough that we don't care
23:26:08
aeth
In math, you can tell from context if the writer made a precedence mistake. Computers aren't that good (and have less context available)
23:36:08
makomo
not sure if anyone's familiar with it, but you basically have tricks like "A = |0><0| defines an operator" so that when you apply it to some state |phi> you get A |phi> = |0><0||phi> = |0><0|phi> which is really just |0> <0|phi> where <0|phi> is the scalar product"
23:41:20
jcowan
I like the Kotlin/Ada attitude: overload operators, fine; invent your own, not fine.
23:54:43
didi
Can I write a destructuring lambda list that takes only the N first elements? For example (that doesn't work), (destructuring-bind (a) '(1 2) a), and I'm only interested in the variable `a'.
0:02:09
fiddlerwoaroof
The biggest pain-point of my objective-c FFI is that everything crashes when I accidentally send the wrong selector to an objective-c object
0:40:59
elderK
makomo: I was dream-working on the backquote stuff. :) I have been walking through this, testing it in the REPL at different points: https://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node367.html
0:41:58
makomo
although, this is just the appendix. the actual section of the book goes into more detail
0:42:20
elderK
I've basically been trying to figure out which parts of his code, applies which rules.
0:42:47
elderK
I've also been feeding his code some stuff, but also "doing the backquote thing" by hand, following the rules. Then comparing his output against my own.
0:45:25
makomo
are you referring to the fact that he just takes the CADR of the thing (ignoring any other values)?
0:46:10
elderK
In the do-loop, he verifies that the form is (unquote something) rather than (unquote something something something)
0:48:05
elderK
Off topic, my eyes are really starting to frustrate me. Most of the time, I don't really... the deficit so much. But right now, I am. I have a vertical split - one side, code. The other side, REPL.
0:48:42
elderK
And my monitor is wide enough that I can't really see each split at the same time. So, when I look at the REPL, I can't see the code.
0:48:51
elderK
And my right eye, the one that works, is shit enough that when I see the code, the REPL is blurry.
0:52:46
makomo
elderK: hah yeah, it really does ignore the CDDR in the above case, while checking it in the case below, interesting
0:53:36
makomo
however, you would only ever hit the error if you intentionally went and malformed the input to backquote. using the reader macros $, %, %@, etc. you're sure that the invariants will hold and no error will occur
0:55:23
makomo
tbh i never actually took a close look at his implementation of backquote, but i've been meaning to do it for some time
0:57:12
makomo
a thing that would be fun to make is a backquote expander but for humands -- it would produce a step-by-step expansion of the backquote, telling you which rule it applied at every step :-)
0:58:50
elderK
makomo: Yeah, that's what I'm thinking. Like, I want to make something, to continue "applying / practicing" CL. But I also want to nail these rules. So, maybe writing an "expander" isn't a bad exercise. :)
0:59:36
elderK
I mean, it would just end up being my own spin of what he made. I'd write it from scratch, doing it based on the rules. But in the end, it'll just be what he's done. Still, I think there's something to be said for doing it yourself, your way, to really... nail something.
0:59:49
makomo
elderK: yet another interesting thing is the "Meta Unquote Protocol (MUP)" which fare talks about in his fare-quasiquote. take a look if you're interested
1:00:36
elderK
I want to get to the point where I can at least /read/ and understand nested backquotery. Like, once-only.
1:01:46
elderK
Aye. But I also want to learn about tree walking and stuff, too. So, this seems like a two-for-one kinda deal :D
1:01:50
makomo
the problem with that particular implementation of once-only is that it's hard to follow the different tiers of evaluation, even when you know what the backquote conceptually does
1:02:58
elderK
Aye :) I'd like to verify my... "conceptual solution" to the once only problem. Just to make sure I'm on the right path. I couldn't implement it, because I couldn't figure out the BQ nesting. But, I'm pretty sure I know exactly what needs to be done.
1:03:39
makomo
in practice, you'll only ever see double backquotes. anything above that is overkill or is for pedagogical purposes only :-)
1:05:30
elderK
In a nutshell, we need to create some "names for the evaluated things." This is the first level. So, we "bind" the result of evaluating whatever forms we were passed. The next step, is creating names for those bindings. You can't just say (,symbol ,gensymed) because the "symbol" may not be a symbol - it may be a value or an expression - so you have to gensym to create placeholder names, so that you can have (gensymed-name-for-symbol
1:05:30
elderK
gensymed-storage-for-the-value). Then finally, you need to make it so that "symbol" means "gensymed-name-for-symbol" wherever ,symbol appears in the body of the thing we're wrapping. If that makes sense :P
1:06:38
elderK
I.e. Cache the results of evaluating the thing. Then create a binding of NAME -> CACHED. Then have some way of having ORIGINAL_NAME -> NAME
1:11:10
makomo
elderK: not quite. the first tier of gensyms is so that ONCE-ONLY is hygienic, i.e. so that the macro using ONCE-ONLY doesn't end up unintentionally capturing some symbols. the stuff that's bound (within the user macro) to these tier-1-gensyms are tier-2-gensyms (generated within the user macro, every time the macro is called)
1:12:55
makomo
the tier-2-gensyms are the ones used in the expansion of the user macro. finally, the provided variables are rebound to the value of the tier-1-gensym (i.e. the tier-2-gensym used for that particular variable) within the user macro (so that when you use it somewhere, you're actually using the tier-2-gensym instead of the original expression)
1:14:08
makomo
once the user macro is defined, the tier-1-gensyms are set in stone and done -- they're generated once (assuming compilation), when your macro is defined and when ONCE-ONLY is expanded
1:14:50
makomo
this is so that nested usage of the user macro doesn't accidentally end up doing variable capture/shadowing
1:18:11
makomo
#:ONCE-ONLY848 is a tier-1-gensym, and you can see how it's "set in stone" ("hardcoded") within the definition of HI
1:18:31
elderK
One thing I'd like to have, and I had trouble with, was gettin ga feel for what stuff was going on.
1:18:49
elderK
But, that didn't really give me a complete feel for what the macro was doing - just the "expansion"
1:19:11
makomo
the user macro HI generates the tier-2-gensym #:X852 and makes that the new value of the user macro argument X, so that you can transparently refer to it
1:19:25
makomo
you can see that the tier-1-gensyms never appear in the expansion, only the tier-2-gensyms do
1:20:38
makomo
the expansion of ONCE-ONLY might be a bit hard to read... until you learn the backquotes rules! :-)
1:20:55
elderK
makomo: When you were figuring out once-only, did you do it all yourself, or did you like, study other implementations and figure it out that way?
1:21:00
makomo
note that in this case, there are no nested backquotes within the expansion (it might look like it though)
1:21:19
makomo
elderK: it was mentioned in ONCE-ONLY which gave me a vague idea, and from that point i studied it myself
1:21:59
makomo
the thing that's mysterious is the 2nd argument that can appear for every symbol in ONCE-ONLY
1:22:08
elderK
I found PCLs explanation of once-only's intent clear. But it's explanation of backquote, etc, nonexistent.
1:22:44
elderK
Yeah :) I think I'll write a little "backquote expander." I'm not sure if that's the right name for it.
1:24:05
makomo
except that ONCE-ONLY can't know that "a-sym", etc. are safe names to use, so it has to use gensyms (tier-1-gensyms)
1:26:13
makomo
but once you understand the rules, you can see how the upper backquote and the lower backquote are "at the same level" and are conceptually "merged"
1:27:06
makomo
(provided that <form> doesn't start with @, in which case you have comma-at instead of comma (this is the caveat mentioned in the CLHS btw!))
1:28:18
elderK
The ,@ just says "Yeah, patch it into the output, directly." Which is what ,<form> would do in this case.
1:28:48
elderK
Where as ,@,@something would say "patch ,@something into the output", then ,@something would be expanded at the next .... level?
1:29:46
makomo
,@,@something would (after 1 evaluation) produce ,@<value-of-something-1> ... ,@<value-of-something-n>
1:30:04
makomo
these elements of the list given by something now have to be forms that will be evaluated as part of the 2nd evaluation!
1:30:59
elderK
THis is where I get a bit confused with terminology. The left-most , applies to the innermost backquote.
1:31:20
makomo
i won't spoil the fun of figuring out what the 2nd argument in a ONCE-ONLY spec does :-)