freenode/#lisp - IRC Chatlog
Search
0:34:56
dlowe
there is also a print-unreadable-object macro for easily producing a print-object output in a standardized manner
0:36:50
aeth
dlowe: uh, two issues with that first method: one you said foo instead of object in the print... and two you mae a recursive print that made my SBCL unhappy
0:37:21
aeth
you probably just wanted this (defmethod print-object ((object foo) stream) (format stream "this is my foo object")) ; test with (make-instance 'foo)
0:38:15
aeth
you probably always want "print-unreadable-object" like this: (defmethod print-object ((object foo) stream) (print-unreadable-object (object stream :type t :identity t)))
0:38:46
dlowe
you know, I think I made that recursive print mistake the first time I made a print-object method too
0:39:33
aeth
(defmethod print-object ((object foo) stream) (print-unreadable-object (object stream :type t) (format stream "~A" 42))) ; pretend 42 is an accessor on foo, it isn't here so you can test it with (defclass foo () ()) and (make-instance 'foo)
0:40:26
aeth
if it's too verbose you can write a macro that hides all of that except for the "~A" 42 part and maybe optionally :identity t
0:41:04
remexre
I'm trying to abstract that all down to (define-print-object CLASS-NAME (&rest SLOTS))
0:42:48
aeth
remexre: (defmacro define-print-object (class (&key (type t) identity) &body body) `(defmethod print-object ((object ,class) stream) (print-unreadable-object (object stream :type ,type :identity ,identity) (format stream ,@body))))
0:43:45
aeth
remexre: if you *just* want to get it down to the slots, then you can abstract it a bit more, for instance, generate a FORMAT for every object in body (easier than generating a more advanced FORMAT string)
0:44:21
remexre
the body's what I want to generate though (largely because I don't wanna have to internalize the pretty printer)
0:45:31
aeth
remexre: right, so then process body to generate a (format stream "~A" ,foo) for every foo in body, and do a bit more additional processing if you don't want to have to do a slot access or accessor call in the body, either
0:46:00
aeth
then it'd wind up looking like (define-print-object foo () a b c) ; for slots or accessors a b and c, depending on which way you go
0:46:17
remexre
the "a bit more processing" seems non-trivial when pretty printing and such get involved
0:46:38
remexre
or at a minimum, I can't figure out how to get the pretty-printer to do what I want :P
0:55:39
aeth
remexre: personally I'd do it manually with the version that I provided, if I even wrote a macro. something like this: (define-print-object foo () "~A ~A ~A ~A" :foobar (foobar foo) :quux (quux foo)) ; modify the macro to say (,class ,class) instead of (object ,class) so you can do this
0:57:39
aeth
That then should say #<FOO :FOOBAR whatever :QUUX whatever> or #<foo :foobar whatever :quux whatever> depending on your *print-case*
0:59:12
aeth
If FORMAT doesn't do what you want, you're going to have to play with other print/write functions on the stream stream
0:59:46
remexre
(let ((big (loop for i upto 20 collect i))) (print-unreadable-object ((make-instance 'foo) *standard-output* :type t) (format t "~s ~a ~s ~a" :bar big :baz big)))
1:02:22
edgar-rft
akoana: the particular problem with my (read-from-string ...) hack is that it makes it too easy to inject malicious code into a running Lisp program. It's always better to check user data from the outside world via parse-integer or some other appropriate way first.
1:02:26
remexre
really I want https://homepages.inf.ed.ac.uk/wadler/papers/prettier/prettier.pdf for common lisp :P
1:03:38
aeth
akoana, edgar-rft: And *read-eval* isn't the only issue so it's best to use a library that is a known-safe read
1:06:13
aeth
remexre: Well, ~% will get you a newline but it still might not quite give you want you want. You might be able to solve it in one format string but it's like regex... you might not be able to read the line when you're done.
1:07:15
remexre
yeah, I'm doing this in the process of throwing away a format string I don't remember writing (committed at 5AM, sooooo) that's mostly punctuation
1:07:41
remexre
and ideally instead having loads of write, pprint-indent, pprint-newline, etc. calls
1:08:00
aeth
well, I've never really messed with the pprint stuff, I mostly just mix write-foo and format
1:09:48
remexre
yeah, I'm getting dangerously close to the point where I write my own implementation of the paper I linked above :P
2:22:20
White_Flame
duckduckgo always seems to find clhs.lisp.se instead of lispworks.com when searching for clhs nowadays. I wonder why that is
2:27:29
no-defun-allowed
You could fix the indentation and move the ecases to alists or some other associative structure.
2:28:04
no-defun-allowed
You should make sure Emacs doesn't put out tabs, since text viewers tend to disagree on what size they are.
2:28:46
no-defun-allowed
(coerce <number> 'float) is better written as (float <number>) and you don't have to write FIRST as FST because CL is a Lisp-2 and names won't be shadowed like that.
2:29:42
no-defun-allowed
(+ (* first 10) second) is probably an easier to read way of putting the bands together at the end, too.
2:29:42
White_Flame
since the first & second reusde the exact same lookup, you should defer that ot a function
2:31:06
aeth
without a second argument it returns either the number itself if it's already a float, or the number as a single-float. So (float 1d0) is 1.0d0 but (float 1) is 1.0f0
2:31:40
aeth
If you're using float imo you want to know what type of float you want (single or double) and provide a "prototype" as 1f0 or 1d0 (or if your lisp supports it, 1s0 or 1l0 as well)
2:34:04
aeth
vms14: well, (coerce foo 'float) will always be single-float if it's not already a float, making it identical to FLOAT's behavior with no arguments afaik
2:35:05
aeth
Well, I tend to use (coerce foo 'specific-float) or a function that wraps that to make it shorter because using 1f0, 1d0, etc., to specify the type looks ugly even though the compiler uses the same thing to implement it
2:35:31
aeth
but if you're doing (coerce foo 'float) then that behavior is identical to (float foo) so FLOAT might be better
2:36:07
aeth
vms14: as for "I'd like to not get used to doing that", the thing is, you should write idiomatic code where possible in the language that you're writing imo
2:37:10
aeth
it's idiomatic in CL to have a foo stored in the variable foo of type foo created with the function foo... because if that feature's there why not use it?
2:38:32
aeth
I'd also personally define member types for those cases so it's a type error before the ecase happens. I'd leave that as ecase. The compiler should optimize the else error part.
2:38:58
aeth
and it's just more obvious what the issue is if it's a type error instead of an ecase error
2:43:28
aeth
vms14: what you could do is you could write a macro to define a member type and a trivial ecase function for each of your entries.
2:43:31
aeth
maybe something like (define-member-with-ecase (type-name function-name) :foo 0 :bar 1 :baz 2 :quux 3) which then expands to something like `(progn (deftype ,type-name () '(member :foo :bar :baz :quux)) (defun ,function-name (,your-gensym-here) (check-type ,your-gensym-here ,type-name) (ecase ,your-gensym-here (:foo 0) (:bar 1) (:baz 2) (:quux 3))))
2:44:58
aeth
Then you have a bunch of top-level defines for each of those long lists and you've effectively created pseudo-enums out of MEMBER types with ECASE
2:54:42
aeth
vms14: a member type just goes through the list and tests to see if it's eq (iirc) to a member of the list
2:55:06
aeth
vms14: a '(member :foo :bar :baz :quux) probably compares the variable to all four to see if it's EQ and if not there's a type error
2:55:48
aeth
You don't need it, if I was writing the macro I suggested, I would start with just generating the case, and later add the deftype
2:58:35
aeth
vms14: usually just the member type is good enough, it's only requiring a macro because you want an actual enum (i.e. some known integer associated with the symbol), not just the emulated enum via member types
3:00:40
aeth
(define-member-with-ecase (type-name function-name) :foo 0 :bar 1 :baz 2 :quux 3) or define-enum or whatever you call it is fairly simple conceptually. You have a plist body, you iterate it manually or with e.g. alexandria's plist iteration macro, and then you process it twice. Once just takes the keywords, for the member type, and the other generates the ecase "enum" function that returns the enum integer for the symbol
3:00:57
aeth
so it doesn't take much to have real(ish) enums even though they don't exist, at least not enumerated
3:03:13
aeth
You could even get fancier with the syntax if an explicit call to an enum function isn't purist enough of an enum for you, but... that's probably pushing it.
3:04:14
aeth
And this isn't even the only way to do it. Another (perhaps more direct) way just defines a bunch of constants. That's probably the other common one.
3:04:21
vms14
for a simple enum without letting you change the order, I guess a simple list could work
3:05:15
aeth
You could just have something that does e.g. a symbol-macrolet or something and gives you a locally scoped enum.
3:20:14
aeth
with ":foo 0 :bar 1 :baz 2 :quux 3" I'm assuming you want to control the number on each because otherwise that breaks the plist assumption unless you have some default ignore-me symbol like _ or you use alists
3:21:03
aeth
if you just want a number, ":foo :bar :baz :quux" is simpler, but if you want it to be optionally defined, it gets complicated. Probably best to make it ":foo :bar (:baz 42) :quux" in that case
3:23:26
aeth
that syntax is better if you're not going to define it for most cases, plist syntax is better if you're going to define it in all cases
3:23:50
aeth
You can use loop at macro expansion time to generate the numbers that aren't provided (skipping over any that are already provided, which is the one complication there)
3:24:52
aeth
Then put those functions in separate files, or in eval-when and you get a trivial one-line macro
3:26:24
vms14
in the same sense no perl programmer is a perl programmer if does not know to use regexp
3:48:24
beach
minion: memo for vms14: You should not mix quantities and units like that. Use the quantities everywhere: resistance, tension, current.
3:49:54
beach
Americans are particularly sloppy in that respect. Not only do they use "voltage" when they mean "tension", but they also use things like "mileage" and "footage". It is really dumb, because several quantities can use the same unit.
3:52:24
beach
You don't say "what is your inchage?". You say "What is your height?" or "How tall are you?". And you don't say "what is your poundage?" (which in the UK would be "what is your stonage?"). You say "What is your weight?".
5:19:25
tourjin
if i opend split window with C-x 3 , and M-x tetris on left window. after I opened a file on left window. what am i supposed to do with tetris? how can I remove tetris? if I close the file, I see tetris again. I mean I like to remove tetris from current emacs memory. how can I unload modules I loaded?
5:59:14
ck_
C-c C-k 'kills' a buffer; C-x C-b displays a list of buffers you can navigate through, pressing 'k' on them marks those for removal, 'x' applies the changes.
5:59:44
ck_
these are pretty fundamental and I'd advise you to please go through the manual before asking those kinds of questions; there's also #emacs
6:02:25
ck_
tourjin: C-h t gives you the tutorial. work through that one. But as you noticed by my mistaking C-c C-k for C-x k, after a while there's not really those letters on your mind anymore, your fingers just press the buttons
6:19:46
White_Flame
does the standard RANDOM functionality allow seeding the random state in a way that is reliably repeatable?
6:21:34
no-defun-allowed
I don't think the nature of the random number generator is specified in CL, so there can't be a number that maps to a random state.
6:21:59
White_Flame
yeah, it seems that the only thing you can do is grab the current, or make a new fully randomized one
6:22:23
White_Flame
but I'd like to seed it in some way that, regardless of restarting the image from scratch, it can generate a repeatable sequence
6:22:33
no-defun-allowed
At least on SBCL, CCL and CLISP, you can print the random state readably though.
6:23:19
White_Flame
(making a another-language-in-CL, where that language wants an int-seedable PRNG)
6:48:17
Shinmera
White_Flame: you can't do that portably, and that's the primary reason I started writing some RNGs myself.
7:31:37
aeth
if ECL and SBCL can seed RNG, and you don't care about the seed being portable, then you could write a portability library around seeding (SBCL's random seed is pretty straightforward)
7:32:12
aeth
and that portability library would work on every implementation if it just falls back to not doing anything if it can't seed
7:48:34
jackdaniel
one thing is that to my knowledge distribution of rng's is uniform and I'm not aware of cl implementations allowing changing that
7:48:49
jackdaniel
so if you need non~uniform distribution indeed writing a library seems to be the best choice
9:06:00
tfb
White_Flame: all implementations can print random-state objects so they can be read in the same implementation
9:13:55
tfb
I guess I don't understand the requirement to seed the PRNG from an integer. That means it can only have as many bits of state as are in a (presumably) fixnum
9:14:32
tfb
But to answer your original question: yes, you can seed a CL RNG in a way which is repeatable in an implementation, just not with an integer
9:14:44
tfb
I guess I don't understand the requirement to seed the PRNG from an integer. That means it can only have as many bits of state as are in a (presumably) fixnum
9:17:27
tfb
Shinmera: CL has that (within an implementation). If you want cross-implementation portability you necessarily have to use a common PRNG algorithm
9:17:32
White_Flame
I mean sure, an integer is as arbitrary as any random-state object. But given source code that seeds with an integer, I can't convert that into a random-state object sensibly
9:18:57
tfb
White_Flame: yes, obviously you're just dealing with a language with a deficient spec, that's just going to make life hard.
9:37:04
White_Flame
These ,@ clauses should line up, shouldn't they? Does Tab align them probably in your emacs/slime? https://pastebin.com/hSdMmWET
9:58:41
White_Flame
If one of my macro parameters is a backquoted list, can I append to it and add comma terms somehow portably?
10:00:06
no-defun-allowed
Though fare-quasiquote replaces the quasiquote reader macros with something consistent.
10:05:55
White_Flame
ACTION is moving from triple-backquote to double-backquote and making it less general in order to work
10:07:56
no-defun-allowed
ACTION moves away from White_Flame, unsure how triple backquote was an attempt to start with
10:08:26
MichaelRaskin
Judging from painlessness of it for Agnostic Lizard, I think that most of the options are relatively sane
10:08:52
White_Flame
no-defun-allowed: macro which takes backquoted clauses and builds up a defmacro-building defmacro inside it