freenode/#lisp - IRC Chatlog
Search
1:55:11
jmercouris
I think I should use the defcommand a lot, and see what kind of patterns emerge, and then write a macro to handle these common patterns
1:55:22
Bike
sorry i don't get the buffer thing, i don't have much context for your program and i don't do that much emacs programming
1:55:24
jmercouris
e.g. do I find myself always forming closures around the active buffer, if so, make it one of those options
2:05:21
pransmonkey
In other words, how does `(getf *some-nil-list* :random-sym)` returns a setable location if the list is empty???
2:07:51
pransmonkey
Okay, how does `(setf (getf *some-ni-list* :wtf) 1)` makes `*some-nil-list* to be `(:A 1)`?
2:09:30
zazzerino
iqubic: slime-company is available on melpa. have you followed the instructions on https://www.emacswiki.org/emacs/MELPA to set it up?
2:11:43
pransmonkey
(LET* ((#:NEW592 1)) (LET ((#:NEW1 (SB-IMPL::%PUTF *PS* :A #:NEW592))) (SETQ *PS* #:NEW1) #:NEW592))
2:13:22
Bike
getf has a setf expansion, meaning that when the setf macro gets a getf form it knows what to do with it
2:13:47
Bike
you could also try macroexpanding e.g. (setf (car x) y), which will give you something with rplaca
2:14:45
pransmonkey
Bike: I mean, what is an alternative way of getting the `(setf (getf *ps* :blah) bleh)` result, without getf.
2:17:21
pransmonkey
I fail to think of another way of doing `(setf (getf *ps* :blah) bleh)` which would help me understand the whole thing.
2:17:38
pierpa
pransmonkey: the answer is: you can't do what you are asking using standard CL. Standard CL uses macros which expand to implementation dependent things
2:17:42
pransmonkey
Bike: Thanks, after you have explained, and looking at the macro expension, I understand how it works.
2:17:55
Bike
it's perfectly possible to do the behavior of setf getf without using setf or getf, it's just list manipulation
2:18:15
pransmonkey
What I am trying to know is, whatever, that is the "standard" way of doing it, and it is often that macros map functions passed with completely different things.
2:18:57
Bike
on sbcl there's a compare-and-swap macro that works similarly to setf, in that (cas form ...) is going to macroexpand into something different based on the cas expansion
2:19:20
Bike
conceptually, in (setf (getf ...) ...) the getf form is not a function call, it is a "place"
2:20:09
pransmonkey
So a place isn't necessarily a real memory location or list reference or anything.
2:21:18
sjl
http://malisper.me/getting-places/ is an intro to places if you want a longer explanation
2:21:50
pransmonkey
Bike: I was thinking of place as some kind of pointer or reference, and so `(setf (getf *ps* :non-existence-pointer-or-reference) bleh)` didn't make sense.
2:27:45
iqubic
Quicklisp has already been installed. Load #P"/home/avi/quicklisp/setup.lisp" instead.
2:31:26
jmercouris
iqubic: I'm very ready to say, give up, install portacle, and if you like common-lisp, go ahead and set this up later
2:36:14
Bike
well, just make an .sbclrc if it doesn't exist, and put (load "wherever/quicklisp/setup.lisp") in there
2:45:15
whoman
lisp syntax highlighting should truly be contextual and depth-ual, rather than literal lettered identifiers
2:46:22
Bike
by default slime just does some dumb shit like coloring operator names beginning with "def"
2:47:56
whoman
jmercouris, the question lacks an existential word ?? like "is" or "are" or query words like "when" or "how" ....
2:50:54
jmercouris
trying to make it easier right now to write commands and to customize, then release a package manager, then some quality of life things to make it easier for noobs
3:16:06
pierpa
You should at least say which implementations you are interested in. I seem to remember thare was a library for this for lispworks, but I have not first-hand experience.
3:57:14
whoman
marriage itself is the best tutorial for marriage. imagine reading a how-to for dummies on marriage, written by some dude having one marriage and knowing other dudes having marriages, but still not knowing how your marriage will go. just get married - life is the best teacher
3:57:58
whoman
also some1!!! please help me!!!!!!!!!!!! the topic is still SBCL 1.4.0 and we are a bit further than that
4:03:40
iqubic
whoman: I'm in American High School, so I'm learning a bit of everything at the moment.
4:04:34
pragmaticmonkey
iqubic: Make a lisp dialect, written in lisp, that makes lisp work the way you want to lisp.
4:05:07
pragmaticmonkey
But PCL has some nice, well, practical, exercises: http://www.gigamonkeys.com/book/
4:08:05
beach
iqubic: For the more long-term projects, here is a list of ideas: http://metamodular.com/Common-Lisp/suggested-projects.html
4:11:55
pragmaticmonkey
iqubic: Hahaha, if you follow the book, you can solve the exercise almost with no problem.
4:12:10
pragmaticmonkey
I was surprised how much lisp I had learned by the time I did the mp3 catalog thingy
4:13:13
pragmaticmonkey
I went way further than the book and have `testcat`, `testgroup`, Test-Table like testing.
4:23:55
pragmaticmonkey
For example, the tests are a simple cons cell ( to-be-test exception ) and doesn't need the check macro.
4:32:11
Bike
(defun transfer (x) (if (plusp x) x 0)) (defun neuron (weights inputs) (transfer (apply #'+ (first weights) (mapcar #'* (rest weights) inputs))))
5:02:23
Pixel_Outlaw
iqubic, for what it's worth there is #lispgames where a bunch of weirdos hang out.
5:15:08
aeth
Anything that's abstract, non-realtime 2D can be written many, many ways. Efficiency isn't really an issue
5:18:37
aeth
And if you don't really have physics, that's a major plus. That makes things much easier.
5:35:58
aeth
Think of game design like a graph. The x axis is similarity to an MMOFPS. The y axis is similarity to Dwarf Fortress. Difficulty to implement is roughly how far that game is from 0. 2048 is pretty close to 0 on that graph.
5:36:53
aeth
(And DF-style complexity would be much easier to write in CL than MMOFPS-style complexity.)
6:04:43
aeth
Lisp's local variables are (by default) lexically scoped. They behave like you expect in most programming languages. Lisp's global variables are dynamically scoped (unless constant or implementation-specific). This is rare in languages these days.
6:05:55
aeth
Dynamic scoping basically means that the variable refers to the most recent binding. So if you do (let ((*standard-output* some-new-stream)) (format t "Hello, world!~%")) it will print to some-new-stream even though you told format to use t (i.e. *standard-output*)
6:06:30
aeth
That's because you don't have to pass the variable in, it checks the most recent binding
6:07:26
aeth
Here's the exact definition of dynamic scoping: https://en.wikipedia.org/wiki/Scope_(computer_science)#Dynamic_scoping
6:09:08
aeth
The advantages of dynamic scoping are: (1) it's easy to implement, (2) you don't have to pass the variable deep down the call stack (so you could redefine *standard-output* at the start of your program and it will go to the right spot every time you say format t)
6:09:47
aeth
The disadvantages are: (1) it's slower (the compiler has less information because it's dynamic), (2) it often doesn't do what you want and it makes things harder to understand (you never actually know for sure where format t will print, especially in a multi-threaded application)
6:11:57
aeth
You essentially go backwards up a list of environments, looking for the first one that defines foo
6:12:35
aeth
here's an example of lexical scoping: (let ((foo 42)) (let ((foo 7)) (print foo)) (print foo))
6:13:27
aeth
here's another example of lexical scoping: (let ((foo 42)) (let ((bar 7)) (print foo)) (print foo))
6:13:45
aeth
it doesn't see foo in the bar environment, so it uses foo in the outer environment this time
6:14:13
aeth
Actually, in this example, the same thing would happen with lexical and dynamic scoping
6:15:55
aeth
This creates a closure. Because the only function retrieves the value and no function sets the value, the compiler can turn this into a function that constantly returns 42.
6:17:33
aeth
Let's do the same thing with a local special variable (even though special variables in CL are normally global, and you'll see why): (let ((*foo* 42)) (declare (special *foo*)) (defun barfoo () *foo*))
6:19:35
aeth
(The *foo* convention is just so we know that they're special, btw. Your compiler might warn you if special variables do not have *s on either side.)
6:24:35
aeth
It bound *foo* to 42 but *foo* only existed within that dynamic scope and no longer exists
6:24:50
aeth
That's one reason why dynamic/special variables are probably not what you want most of the time.
6:25:54
aeth
Let's get rid of the error with a global: (defparameter *foo* 7) (let ((*foo* 42)) (declare (special *foo*)) (print *foo*) (defun barfoo () *foo*)) ; I added a side effect print statement so you can see that *foo* is 42 inside the let
6:26:26
aeth
iqubic: By convention (and your compiler might warn if it violates the convention) special variables (the CL term for dynamic variables) always have the earmuffs
6:29:28
aeth
the print statement is within the let. If you did a (print (barfoo)) after you define barfoo, it will also be 42.
6:29:55
aeth
But once you're outside of the let, (barfoo) is looking at the global *foo*, it doesn't remember the environment it was defined in. It looks at a dynamic environment.
6:30:53
aeth
iqubic: Here, let me help you. Closures are what we're talking about. Another name for "closure" is "lexical closure".
6:31:20
aeth
The alternative name might help explain why foobar works as expected. It's using a lexical variable.
6:32:33
aeth
If you really want to have fun, let's play with this version: (let ((foo 42)) (defun foobar () foo) (defun foobar+1 () (incf foo)))
6:32:57
aeth
This was a major selling point of Lisp for a long time until everyone started copying it.
6:33:57
aeth
Note, though, that closures require the lexical variables to work. The normal ones, without the earmuffs.
6:35:17
aeth
It remembers the environment in which the function was created. This works for all functions, even anonymous (lambda) ones.
6:36:00
aeth
Both refer to the foo in that environment because there's no foo in the local environment of either function.
6:37:08
aeth
Lots of languages have this, but I never truly understood scope until I programmed in Lisp.
6:39:36
iqubic
I was trying to have a varible foo defined inside the closure, and outside the closure too.
6:42:06
aeth
Everything is nice and contained, and you shouldn't have any surprises when working with lexical variables.
6:42:29
aeth
I mean, it might be a bit surprising that foo increments, but not too surprising if you look at the whole environment
6:43:17
iqubic
yeah. Calling foobar+1 a couple times, then calling foobar shows a number bigger than 42.
6:48:58
aeth
If you're correct, that should similarly stack overflow, instead of producing fifty quintillion forty-two
6:50:32
aeth
You can do this if you want to verify that it will hold in our other case: (let ((foo 42)) (defun foobar () foo) (defun foobar-inc (x) (incf foo x))) (foobar-inc (* 50 (expt 10 18))) (foobar)
6:52:04
aeth
In Common Lisp, integers are the mathematical integer. The efficient representation is called a fixnum and the inefficient representation is called a bignum. You will be able to go as large as you have memory.
6:52:35
aeth
If the compiler knows that it will stay a fixnum, it will be just as efficient as C. If you forget to do this, at least you still have an integer of some sort.
6:53:09
aeth
In the foobar example, you probably want an integer and not a fixnum. So that's what you get.
6:54:14
aeth
Most cool uses of closures use anonymous functions, called lambda. That way, you don't have to do everything globally.
6:56:23
aeth
Let's make a foo factory: (defun foo (&optional (foo 42)) (values (lambda () foo) (lambda (&optional (x 1)) (incf foo x))))
6:57:25
aeth
You can make it more robust like this: (defun foo (&optional (foo 42)) (check-type foo integer) (values (lambda () foo) (lambda (&optional (x 1)) (incf foo x))))
6:58:52
aeth
You can bind both functions with multiple-value-bind. You can call these functions with funcall. You can do something like this now: (multiple-value-bind (foobar foobar-inc) (foo 42) (funcall foobar-inc) (funcall foobar))
6:59:25
aeth
I wish we still had lisp paste because line breaks probably would help here now that things are getting more complicated.
7:00:17
aeth
The first defun is the same as the second, except the second also checks that foo is an integer, so the user doesn't give it a bogus value
7:00:39
aeth
The defun creates an environment with foo, just like our let, except it lets you define it
7:01:44
aeth
Common Lisp has multiple namespaces. That's why both the function and the variable can use the name foo. That means, though, that to call the anonymous functions you just created, you need to use funcall to tell it to treat a variable namespaced thing like a function
7:02:50
aeth
That's what the multiple-value-bind is for. There are two return values because there are two functions. It's just like let, except it defines it from multiple return values, e.g. this foo will start at -1: (multiple-value-bind (foobar foobar-inc) (foo -1) (funcall foobar-inc) (funcall foobar))
7:03:41
aeth
If you don't like multiple return values you can always put them in a list, vector, standard-object, struct, hash-table, etc. of course.
7:04:34
aeth
The foo environment is stored away in some place that foobar and foobar-inc (formerly anonymous functions, now named) can access
7:06:33
iqubic
but once I make a foo thing, I can no longer seem to call the functions related to foo.
7:07:58
aeth
One is multiple-value-bind. Another is multiple-value-list, e.g. (multiple-value-list (foo))
7:15:39
aeth
(multiple-value-bind (foobar foobar-inc) (foo -1) (setf (symbol-function 'foobar) foobar) (setf (symbol-function 'foobar-inc) foobar-inc))
7:16:08
aeth
You can use symbol-function to define them globally, and then you can use (foobar) and (foobar-inc) as if they were always there
7:20:29
aeth
It's probably handled specially, but in some Schemes, let might be defined as a macro over lambda.
7:22:09
iqubic
For built in stuff I don't care whether a thing is a function, macro, or special form, because they all work mostly the same.
7:22:39
aeth
iqubic: Roughly: (funcall (lambda (x) (format t "~D~%" x)) 42) <=> (let ((x 42)) (format t "~D~%" x))
7:22:58
aeth
iqubic: In some Schemes, the Scheme equivalent of that might be exactly true. I'm sure someone here can tell me why that's not exactly true in CL.
7:25:01
aeth
iqubic: multiple-value-bind actually uses a very similar principle in its implementation, except with multiple-value-call instead of funcall.
7:29:45
aeth
iqubic: A practical example of a let over a lambda is in the utility library alexandria. curry. https://gitlab.common-lisp.net/alexandria/alexandria/blob/e5c54bc30b0887c237bde2827036d17315f88737/functions.lisp#L114-155
7:30:39
aeth
It lets you do this to do partial function application: (mapcar (alexandria:curry #'+ 10) (list 1 2 3 4 5)) => (11 12 13 14 15)
7:31:49
aeth
It lets you do this to do partial function application: (mapcar (lambda (x) (+ x 10)) (list 1 2 3 4 5)) => (11 12 13 14 15)
7:32:22
aeth
curry just creates the lambda for you and makes it a lot more concise (especially if you import curry so you don't see the prefix)
7:37:13
aeth
The worst part about CL is the names. CL chose to be compatible with much older Lisps rather than break compatibility (Scheme broke compatibility). But, hey, I'll take ugly names over many other flaws a language could have.
7:38:29
aeth
Whenever there was a design decision CL chose the uglier, more practical decision. It's designed for industrial use.
7:39:46
aeth
Most of the names are fine, but some older things (including mapcar) don't really follow the language's idiomatic naming style because they predate it.
8:03:16
aeth
Shinmera: Wait, are you telling me that the point of Common Lisp is to be the common Lisp?
10:06:37
beach
How can I implement the standard method combination if I have no evaluator (no compiler, no interpreter)?
10:07:27
beach
You can assume that the methods themselves exist and have been loaded as binary code from (say) a file.
10:19:53
specbot
Standard Method Combination: http://www.lispworks.com/reference/HyperSpec/Body/07_ffb.htm
10:21:01
beach
And you would turn the applicable methods into an effective method which is a function that needs to be created at runtime.
10:21:26
phoe
Your CALL-NEXT-METHOD may simply invoke a method that is found via some dynamic variable.
10:23:11
phoe
If you know that you will want to have a CALL-NEXT-METHOD local function, then you can take a step back and, whenever you compile the methods, simply force them to have an ignorable local function CALL-NEXT-METHOD that refers to some dynamic variable and expects it to be bound.
10:24:36
beach
Related question: Suppose I have a (possibly empty) list of :BEFORE methods, a (possibly empty) list of :AFTER methods, a (possibly empty) list of :AROUND methods, and a (possibly empty) list of primary method. Can I, without any other information, always know what to do when call-next-method is called?
10:24:47
phoe
If it's for bootstrapping, the end user will not be able to notice that they have a function that is global but should have been local.
10:25:47
beach
2. If the list of :AROUND methods is empty, but the list of :BEFORE methods is not, then call all the :BEFORE methods in that order, and then set the list to '().
10:26:17
beach
3. If the list of :BEFORE methods is also empty, but the list of primary methods is not, then pop the first primary method off and call it.
10:26:40
phoe
The algorithm in CLHS seems well-defined. Your code should be able to always guess what to do next.
10:27:16
beach
4. If the list of primary methods is also empty, but the list of :AFTER methods is not, then call the methods on the list in that order.
10:29:00
phoe
Let's assume that you have *PRIMARY-METHODS* that holds the list of all primary methods for a function.
10:29:23
phoe
grab the CAR of this list, rebind the variable to the CDR, call the method-function of the CAR.
10:29:41
phoe
This way, CALL-NEXT-METHOD may refer to the next method by grabbing the CAR of *PRIMARY-METHODS*.
10:31:22
phoe
CALL-NEXT-METHOD can check on *AROUND-METHODS* if the CAR of this list "matches" the CAR of *PRIMARY-METHODS*.
10:33:38
beach
some of which are primary, some of which are auxiliary. No :AROUND method is attached to another method.
10:36:04
beach
Given four lists *AROUND-METHODS* *BEFORE-METHODS* *PRIMARY-METHODS* and *AFTER-METHODS*...
10:36:40
beach
To invoke the effective method, I actually call the global function CALL-NEXT-METHOD, and that one does the following...
10:38:06
beach
2. If *AROUND-METHODS* is empty, it calls all the methods in *BEFORE-METHODS*, then sets that list to the empty list, pops the first primary method off and calls it.
10:38:35
Shinmera
beach: You have to check whether there's a primary method at all first, and if not, error.
10:39:18
beach
3. If both *AROUND-METHODS* and *BEFORE-METHODS* are empty, then if *PRIMARY-METHODS* is empty, then error.
10:39:52
beach
4. If *PRIMARY-METHODS* has a single entry on it, then pop it off, call it, and then call all the methods in *AFTER-METHODS*.
10:40:12
phoe
But if there is no primary method when there are after/or before methods, then it is an error.
10:40:49
beach
Since this is bootstrapping, we can assume that the code is correct, so that CALL-NEXT-METHOD is not called unless it is allowed.
10:42:53
beach
Correct, but if it has a single entry, it is the last one, so the after methods should be called.
10:43:35
phoe
You only call the first one - it is the method itself that may call next methods if it wants to.
10:44:17
phoe
If the method wants to call more, then it must invoke CALL-NEXT-METHOD inside its body.
10:50:31
pjb
aeth: the best thing in CL are the names! If you're not happy with them, you can define your own in your own package! (:use "AETH-LISP") !
10:52:28
aeth
pjb: thanks to specialization-store we now have a (semi-portable) way to easily define type-generic functions on numbers and sequences that behave like #'+ and #'map
10:53:12
aeth
Which means arithmetic functions could be defined to support inline sequence functions and hopefully have no performance penalty with the existing arithemtic functions!
10:56:03
pjb
Well arithmetic with more than two arguments has the inconvenient that the dispatch has to be done by analysing the whole argument list types.
10:56:58
aeth
I think another problem is that arithmetic with vectors/matrices would cons heavily unless there was something fancy going on.
10:57:04
pjb
Well, AFAIK the standard would allow (reduce op arguments), but you'll get more precise results by sorting out the arguments.
10:58:26
aeth
(Also, matrices would have to be represented with 2D arrays, not sequences, or else there's no way to tell them apart from vectors, at least as I just described things.)
11:08:17
aeth
pjb: I think you just pointed out why this wouldn't work, though. Argument lists can be as close to infinite as 64-bits allows (probably the most positive 63-bit fixnum value)