freenode/#lisp - IRC Chatlog
Search
9:10:20
no-defun-allowed
might be a good time to remind people that despite the clhs being quite restrictively copyrighted you can download the CLHS for personal use, and it's only about 15MB including crappy GIF images and all 2300 HTML files
9:11:38
no-defun-allowed
it's 2mb in the targz you get from lispworks so you can do it any time you're bored or have a minute where you're thinking "what language documentation should i download today?"
9:13:43
jackdaniel
here is even better version which is not copyrighted: http://cvberry.com/tech_writings/notes/common_lisp_standard_draft.html
9:14:27
jackdaniel
you may build your own standard draft, change it, annotated it and put it on the website (also use as a pdf with bookmarks - much better to navigate than clhs directly if you ask me, I'm still sold to l1sp.org though)
9:40:28
flip214
no-defun-allowed: also, please contribute to CLUS: https://github.com/phoe/clus-data
9:51:40
ogamita
More worrying is that lisp logs at ccl have been down since login is required on freenode…
10:13:39
no-defun-allowed
If so, subseq works fine, as long as you check the string isn't shorter than your desired length.
13:58:50
heisig
What is the best way to obtain the value of a form that is CONSTANTP, e.g., within a compiler-macro? EVAL?
14:05:22
_death
but there is an issue.. I believe a form may be a constant form but still its value may not be available at that time
14:06:53
_death
for example (defconstant foo 'bar) means FOO is a constant form but at compile-time its value may not be available (for that you'd need eval-when)
14:07:52
flip214
heisig: EVAL won't do - the value might use the wrong binding (global vs. thread-local, etc.)
14:08:19
flip214
it depends on what you're doing with it; perhaps NUMBERP and/or STRINGP is good enough?!
14:08:25
heisig
Hmm, the glossary states a constant form is "any form for which evaluation always yields the same value, ...". Not sure how to interpret that.
14:08:41
flip214
if it's a constant, the compiler will fold it anyway - even without a compiler-macro.
14:09:04
_death
heisig: it means (eq (eval form) (eval form)) => t, given that its value is available
14:09:06
flip214
but I understand the wish to optimize for such cases -- perhaps inlining the "outer" part of a function helps, and that calls some non-inlined inner part?
14:09:55
heisig
flip214: In practice, NUMBERP is probably fine for my case. I just thought there might be an 'official' way to address this problem.
14:10:06
flip214
heisig: that is not sufficient. (IDENTITY *X*) with (DEFVAR *X* 1) will always return 1 (EQL to 1), but any thread that used (IDENTITY *X*) in an argument list might have *X* bound to a different value!
14:11:22
flip214
my CLHS has a few examples; see eg. (constantp '(sin pi)) => implementation-dependent
14:12:16
lieven
the two authors both think the wording is unambiguous, they just disagree about what they meant
14:14:08
_death
flip214: (identity *x*) with *x* naming a special variable won't be a constant form...
14:15:40
heisig
I think I will use (defun conservative-constantp (form) (or (quoted-form-p form) (and (not (listp form)) (not (symbolp form))))) to be on the safe side.
14:16:59
flip214
heisig: " If object is a cons, listp does not check whether object is a proper list; it returns true for any kind of list. "
14:18:45
_death
heisig: still won't pass the symbolp check though.. maybe (and (symbolp x) (constantp x) (boundp x))
14:21:35
scymtym
heisig: what is the purpose of your predicate? is it suitable for your use-case to, for example, consider (+ 1 2) not constant, but #<CLASS …> constant?
14:22:35
heisig
scymtym: The purpose of that predicate was to determine whether a form is so constant that I can EVAL it at any time.
14:26:57
heisig
It's not terribly important for my program. I just thought that maybe there is already an agreed upon way to deal with this situation.
14:27:45
scymtym
moving the evaluation to load time instead of all the way to compile time sometimes works
14:34:05
scymtym
cl-ppcre has an example of this approach and illustrates a caveat: for a long time it did "if (constantp regex env) then (load-time-value (compile-regex regex))". this is wrong if REGEX is constant in ENV but not in the null lexical environment
14:55:15
heisig
I conclude - the right way is to use constantp without an environment and then load-time-value. Thanks everyone!
15:22:25
dim
is there a good documentation somewhere on CL environments and how to use them as a CL user? I'm lacking the practical implications of the idea, and I have no idea how to use &environment in the operators where it exists...
15:23:21
jackdaniel
dim: as it is specified in CL &environment is mostly good for only passing it to other macros
15:23:47
jackdaniel
some important primitives did not get through to ANSI CL, but they were specified in CLtL2
15:24:00
pfdietz
The only thing I have consistently used environments for is as an argument when manually expanding macros.
15:25:04
jackdaniel
dim: for more useful things check out https://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node102.html#SECTION001250000000000000000 (they are defined in both sbcl and ccl, they will be defined in ecl too)
15:42:22
pfdietz
The thing I've used it for is to exploit the environment as a kind of poor man's symbol table. If I have a macro that wants to make declaration-like things visible to lexically enclosed forms, I encode that with macrolets whose only purpose is to be deliberate expanded by other macros to get the information back out again.
16:58:45
sjl_
Is there a guide on how to use a proxy to make quicklisp download over HTTPS so it's not horrifyingly insecure?
16:59:09
sjl_
I know about http://netprophetblog.blogspot.com/2014/02/tool-posting-quicklisp-with.html because it's linked from the docs, but that's about how to layer a SECOND proxy over an existing one.
16:59:59
sjl_
I have tinyproxy running locally. I can e.g. `curl https://beta.quicklisp.org/... --proxy http://localhost:8888` and this works fine
17:00:30
sjl_
but when I tell quicklisp to use that proxy with (ql-config:config-value "proxy-url") it's still making the requests to http://beta.quicklisp
17:01:01
Xach
sjl_: I don't know of a guide, sorry. you can modify ql-http:*fetch-scheme-functions* to use e.g. drakma or something with ssl support.
17:01:29
sjl_
I tried setting (setf ql::*client-base-url* "https://beta.quicklisp.org") but that doesn't affect the archive urls that it fetches, because I think it reads those straight from releases.txt which has the bare http:// in there
17:02:27
sjl_
Xach: running tinyproxy should handle the SSL stuff, I just need a way to tell quicklisp to request https:// instead of http://
17:04:32
sjl_
Is a config option for "Please use HTTPS urls everywhere, I'll provide a proxy for you" something that could be added to quicklisp?
17:05:13
sjl_
I'm not even sure having QL use Drakma would work, because wouldn't it still be requesting http://?
17:06:24
Xach
I think *fetch-scheme-functions* is attractive because everything that fetches flows through it.
17:06:57
sjl_
Oh, so you're saying I can wrap the existing "http" fetch-scheme-function to rewrite the URL and then delegate to the old one
17:07:25
Xach
sjl_: I don't know if that will work - I don't know what the existing one will do with a https URL.
17:08:29
Xach
I mentioned this yesterday, but I have a system that is almost ready to deploy that involves fetching signed things and checking checksums and adding more confidence aside from https.
17:11:23
sjl_
Ah, so the user would download your public key over https (bundled in the initial setup file or whatever) and then this pure-CL implementation of PGP checks that whatever it downloads is correctly signed?
17:11:54
Xach
sjl_: yes. the bootstrap file embeds a pgp signature checker and the initial dist key.
17:12:20
sjl_
That would work, I think. Doesn't really matter if I get MITM'ed if it can be detected before executing the code.
17:13:06
sjl_
And if someone wants to use a dist other than yours, they'd get the author's pubkey securely somehow and add it into the list of keys that QL trusts
17:14:23
Xach
there isn't the web-of-trust component that i know is an important part of a real system. this is my attempt at the best "simple" thing when https isn't easily available everywhere.
17:15:18
aeth
d4ryus: The way I know about to print part of a string is this way: (write-sequence "Hello, world!" *standard-output* :start 7 :end 12)
17:15:49
aeth
d4ryus: In general if you think in sequences, they almost have start/end (or start1/end1 and start2/end2)
17:16:17
aeth
If you only want to print the first n characters than you can just say ":end n" and have no :start
17:17:20
sjl_
Xach: Hmm, well wrapping the fetch-scheme-function didn't seem to work, so I guess I'll just wait for that patch to land.
17:25:47
sjl_
Xach: which seems like it should be okay, but tinyproxy says https://plaster.tymoon.eu/view/1078#1078 and I don't have time to dig into how the request is actually happening
17:31:03
sjl_
depending on what kind of graph you're talking about, I shell out to either graphviz or gnuplot
17:31:25
aeth
Several options. You could take a do it yourself approach and build on top of something like https://github.com/vydd/sketch (2D) or https://github.com/cbaggers/cepl (3D) at the most basic level.
17:33:39
aeth
I've personally had decent success with graphviz, you just need to generate a .dot ("dot dot"?) file. The format is not quite as high level as I would have liked if you want it to render nicely (even though it *will* render with spaghetti connections if written the naive way)
17:34:10
Selwyn
i notice there are quite a few Lispy interfaces to graphviz - cl-dot, s-dot, cl-graph etc
17:37:18
aeth
Not sure if cl-dot supports it but for complicated graphs you probably want to create intermediate blank nodes so you can control the chaos of the long, overlapping arrows a bit.
17:38:58
Xach
sjl_: this isn't quite what you had in mind, but https://plaster.tymoon.eu/view/1079#1079 was my first try. it doesn't actually work and i'm not fully sure why -- (ql:update-dist "quicklisp") fails for me.
17:40:36
aeth
(Coincidentally, A->B is valid dot, that's not what I meant, of course. I meant instead of "A"->"B" you have "A"->"intermediate" [dir=none] and then "intermediate"->"B" where you'd have a separate entry for "intermediate" that makes it a tiny shape. I can't give the CL syntax because libraries could differ)
17:40:37
Xach
no problem, sorry it's not better already - i spent my extra time before work chainsawing a hole through a frozen instead of polishing pgp
17:40:53
Selwyn
aeth: it's a shame that it can't figure out how to render complicated graphs in a nice way. i wonder if it is a particularly hard problem to solve?
17:42:22
aeth
Selwyn: With dot files, you can break things up into a subgraph, and put the tiny intermediate shapes I was talking about as "inputs" to the subgraph area, which can group things a bit. But if something's complicated it's complicated.
17:43:43
Xach
sjl_: ahh, i got the signature of ql-http:fetch wrong. the file fetched is the second value. adjusting ssl-fetch to return (values nil (drakma-fetch-to-file ...)) fixes things.
17:45:09
aeth
Selwyn: If you're okay with your lines looking roughly like -------*------*-----*----> where * is a tiny shape, except in 2D going in various directions (and iirc the polyline instead of smooth style so it stands out less), then you can micromanage the lines when the program would make it do something really bad.
17:45:14
aeth
Of course, this won't work if the graph itself is arbitrary, but it could work for a Lispy preprocessor for fixed data.
17:45:37
aeth
There might be a better, more approved way, but that's what I hacked together last time I had something really complicated
17:45:51
thrig
or with spendy software you can import dot into omnigraffle or maybe visio and then clicky drag stuff around
17:50:27
Selwyn
aeth: thanks for the tips. for now, i am dealing with simple graphs and don't need the output to be too polished
17:50:40
aeth
Imo a hacky .dot (or anything else visual) is at least in theory easier to update by updating generating .lisp file than hand cleaning it
17:53:38
aeth
Selwyn: You should check to make sure the library you settle on using can handle generating "subgraph cluster_foo { ... }" then because that's probably the most complexity you'll need (e.g. something that's very clearly in two or three semi-independent parts).
17:54:34
aeth
Right at the main page here https://graphviz.gitlab.io/ you can see the subgraph cluster feature in the first screenshot here: https://graphviz.gitlab.io/_pages/Gallery/directed/cluster.png
17:55:26
aeth
Without that, graphviz will basically group the nodes in the way that makes the most sense for it, not necessarily the way that makes the most sense for humans
18:52:24
asarch
One stupid question: generic dispatch is the same as polymorphism (both happen at run-time)?
19:01:01
aeth
But without fancy libraries like those, the only polymorphism you will see that are not at runtime (afaik) are number and sequence and array (and possibly stream?) operations that you cannot (portably) define yourself.
19:01:57
aeth
And all of these (afaik) will default to a slower runtime generic if there is not enough information at compile time.
19:11:38
aeth
Typecase is great when there's one, or maybe two, arguments that you want to use the typecase on. Beyond that you would essentially have to build a truth table (except with potentially more than two values) out of nested typecases.
19:14:01
aeth
Just assume your dispatch is using a typecase for list or sequence (with sequence coming second so it's really sequence-and-not-list), which seems fairly common. If you want to be able to mix the two types then one argument is just 2, two arguments is 4, three arguments is 8, etc. Very similar to writing out the left hand side of a truth table.
19:18:12
aeth
What's nice about typecases, though, is that you could have the sequence-generic version in an inline function and have it consist only of an etypecase/ctypecase that calls either the list version optimized for conses or the other-sequence version assuming O(1) elt access (really, it's written with vectors in mind, but it's also a fallback for implementations with extensible sequences).
19:19:39
aeth
With the sequence inline typecase design, if the type is known to the compiler and the function is actually inlined by the compiler then the inline etypecase/ctypecase dispatch is removed and it directly calls the non-generic version. Otherwise, it has a very cheap dispatch left in there without inlining a potentially huge function.
19:19:55
aeth
It's a neat trick that can be an alternative to generics, especially if you only have one sequence argument.
19:26:10
jasom
I usually just start with generic functions and then if profiling tells me it's a problem I rewrite the parts that need it.
19:27:06
aeth
jasom: Yes, this is just a very special case where the performance gains and how to get them are a fairly simple pattern.