Prev: Do as the Romans do
Next: managing large table of data
From: Leandro Rios on 1 Feb 2010 17:43 slash dot <tyntyfax(a)gmail.com> writes: > > Well, you are an alert reader. "Unless your code does (read)..." > My code doesn't (read), it gets the lambdas from an array and > picks them by index as needed. Some of the lambdas need an argument, > some don't. The caller inspects the lambda by one way or the other > and passes an argument if needed. The alternative is to make all > lambdas uniform in that all of them accept an argument, but some > simply ignore it. However, there is a problem: the caller traverses > a sequence and leaves maintaining the iterator to other parts of > the system. If the caller fetches a value, passes it to the lambda, > and the lambda does not need it, the system gets out of sync. The > caller > does something like > > (funcall my-lambda (next-item)) > > where (next-byte) advances the iterator. If the called lambda > does not consume the passed value, it is supposed to be process > by a subsequent call to a (potentially other) lambda. Do you have control about how lambdas are generated? If so, it would be easy to do: (funcall my-lambda #'next-item) where all lambdas would take a parameter and would behave like this: Lambdas not using next-item: #'(lambda (item-fn) (declare (ignore item-fn)) ... stuff ...) Lambdas using next-item: #'(lambda (item-fn) (let ((item (funcall item-fn))) ... stuff with item ...)) Would that be a viable solution? It's just ANSI CL :) Leandro > > I hope you are still with me at this point. This route of a > lambda-array saves a lot of code, because this representation > of my data requires no parsing. Instead of deciphering some other > representation and dispatching accordingly, the caller simply > calls the unearthed lambda. For this to work, however, the caller > must know whether the lambda will need the "next" item or not. > > What I can exploit here is the lucky coincidence that lambdas > that need that particular data item expect it as an argument, > and that this fact is reflected in the argument list. By inspecting > the argument list, the caller can infer whether it is supposed > to advance the iterator or not. Isn't that the lisp way?
From: slash dot on 1 Feb 2010 17:45 On Feb 1, 8:11 pm, p...(a)informatimago.com (Pascal J. Bourguignon) wrote: > slash dot <tynty...(a)gmail.com> writes: > > On Feb 1, 2:02 am, Paul Donnelly <paul-donne...(a)sbcglobal.net> wrote: > >> slash dot <tynty...(a)gmail.com> writes: > >> > lisp is famous for is reflection capabilities, and, > >> > indeed, a function like '10+' is reported to be > > >> > #<FUNCTION 10+ (NUMBER) (DECLARE (SYSTEM::IN-DEFUN 10+)) > >> > (BLOCK 10+ (+ 10 NUMBER))> > > >> > in clisp. > > >> > (Disturbingly, this only works if I bind #'10+ to a variable and > >> > evaluate > >> > the variable, but that's a clisp implementation detail, right? RIGHT?) > > >> > So my question is: how can I inspect functions to find out how > >> > many arguments it has, for example? > > >> Isn't that the sort of thing you should already know? > > > My code needs a largish number of very similar lambdas. > > Right now the code does what you suggest. It maintains > > the information on its arguments in an extra data structure. > > The argument information is put into the data structure > > when the lambda is declared. This DOES work, but I was > > curious about automating this. > > If your code already does it, then it is already automated. > What more automation do you want? > > Unless your code does (read) and you have to type manually the > argument list of each function when your code needs it... > > -- > __Pascal Bourguignon__ [ The other, similar, post is botched. Here is the improved edit. ] Well, you are an alert reader. "Unless your code does (read)..." My code doesn't (read), it gets the lambdas from an array and picks them by index as needed. I do this, because these lambdas represent data, not code. I typed all those lambdas in by hand, automation (abstraction) is possible, but this would make it harder for other programmers to verify the correctness of my data. This route of a lambda-array saves a lot of code, because this representation of my data requires no parsing. Instead of deciphering some other representation and dispatching accordingly, the caller simply calls the unearthed lambda. For this to work, however, the caller must know whether the lambda will need the "next" item or not. The caller does this with a lambda retrieved by index: (funcall my-lambda (next-item)) ; note the call to 'next-item' ; this is the argument we are ; talking about However, there is a problem: the caller traverses a sequence, calling lambdas for processing data items in packs that are of various length. The caller leaves maintaining the iterator to other parts of the system. If the caller fetches a value, passes it to the lambda, and the lambda does not need it, the system gets out of sync. If the called lambda does not consume the passed value, it is supposed to be process by a subsequent call to a (potentially other) lambda. What I can exploit here is the lucky coincidence that lambdas that need that particular data item expect it as an argument, and this fact is reflected in the argument list. By inspecting the argument list, the caller can infer whether it is supposed to advance the iterator or not. Isn't that the lisp way?
From: slash dot on 1 Feb 2010 17:49 On Feb 1, 11:43 pm, Leandro Rios <leandroprograma...(a)gmail.com> wrote: > slash dot <tynty...(a)gmail.com> writes: > > > Well, you are an alert reader. "Unless your code does (read)..." > > My code doesn't (read), it gets the lambdas from an array and > > picks them by index as needed. Some of the lambdas need an argument, > > some don't. The caller inspects the lambda by one way or the other > > and passes an argument if needed. The alternative is to make all > > lambdas uniform in that all of them accept an argument, but some > > simply ignore it. However, there is a problem: the caller traverses > > a sequence and leaves maintaining the iterator to other parts of > > the system. If the caller fetches a value, passes it to the lambda, > > and the lambda does not need it, the system gets out of sync. The > > caller > > does something like > > > (funcall my-lambda (next-item)) > > > where (next-byte) advances the iterator. If the called lambda > > does not consume the passed value, it is supposed to be process > > by a subsequent call to a (potentially other) lambda. > > Do you have control about how lambdas are generated? If so, it would > be easy to do: > > (funcall my-lambda #'next-item) > > where all lambdas would take a parameter and would behave like this: > > Lambdas not using next-item: > > #'(lambda (item-fn) > (declare (ignore item-fn)) > ... stuff ...) > > Lambdas using next-item: > > #'(lambda (item-fn) > (let ((item (funcall item-fn))) > ... stuff with item ...)) > > Would that be a viable solution? It's just ANSI CL :) If nothing else, this is a good idea. I see no reason why this should not work, thanks. However, I won't know before tomorrow, because there might be a non-obvious spoiler... > > Leandro > > > > > I hope you are still with me at this point. This route of a > > lambda-array saves a lot of code, because this representation > > of my data requires no parsing. Instead of deciphering some other > > representation and dispatching accordingly, the caller simply > > calls the unearthed lambda. For this to work, however, the caller > > must know whether the lambda will need the "next" item or not. > > > What I can exploit here is the lucky coincidence that lambdas > > that need that particular data item expect it as an argument, > > and that this fact is reflected in the argument list. By inspecting > > the argument list, the caller can infer whether it is supposed > > to advance the iterator or not. Isn't that the lisp way? > >
From: Thomas A. Russ on 1 Feb 2010 17:46 slash dot <tyntyfax(a)gmail.com> writes: > Well, you are an alert reader. "Unless your code does (read)..." > My code doesn't (read), it gets the lambdas from an array and > picks them by index as needed. Some of the lambdas need an argument, > some don't. The caller inspects the lambda by one way or the other > and passes an argument if needed. The alternative is to make all > lambdas uniform in that all of them accept an argument, but some > simply ignore it. However, there is a problem: the caller traverses > a sequence and leaves maintaining the iterator to other parts of > the system. If the caller fetches a value, passes it to the lambda, > and the lambda does not need it, the system gets out of sync. The > caller > does something like > > (funcall my-lambda (next-item)) > > where (next-byte) advances the iterator. If the called lambda > does not consume the passed value, it is supposed to be process > by a subsequent call to a (potentially other) lambda. OK. What about making all of the functions uniform in not taking ANY arguments and having those that need data just call (NEXT-ITEM) whenever they need the information? Do these functions have any independent use outside of this iteration environment? In any case, I think it would still be fairly simple to store the arity of the function along with its code if that turns out to be what you need to do. > > I hope you are still with me at this point. This route of a > lambda-array saves a lot of code, because this representation > of my data requires no parsing. Instead of deciphering some other > representation and dispatching accordingly, the caller simply > calls the unearthed lambda. For this to work, however, the caller > must know whether the lambda will need the "next" item or not. Well, assuming I understand your description properly, it seems that what you have effectively done is to pre-compile the parsing of the the data stream into a series of lambda expressions that are each invoked on parts of the input in turn. It seems that these expressions must (at least some of them) have side effects, or else calling them wouldn't really have any effect. Do you make any use of the return value of the expressions, or all they called solely for their side effects? > What I can exploit here is the lucky coincidence that lambdas > that need that particular data item expect it as an argument, > and that this fact is reflected in the argument list. By inspecting > the argument list, the caller can infer whether it is supposed > to advance the iterator or not. Isn't that the lisp way? You could do that. On the other hand, you could restructure things as noted above so that routines that need arguments will just fetch them rather than making their caller do it for them. Certainly from the point of view of a rather uninformed caller, that would be appealing from a uniformity of interface point of view. -- Thomas A. Russ, USC/Information Sciences Institute
From: Pascal J. Bourguignon on 2 Feb 2010 00:18
slash dot <tyntyfax(a)gmail.com> writes: > On Feb 1, 6:11�pm, Duane Rettig <du...(a)franz.com> wrote: >> On Jan 31, 3:34�pm, slash dot <tynty...(a)gmail.com> wrote: >> >> > lisp is famous for is reflection capabilities, and, >> > indeed, a function like '10+' is reported to be >> >> > � � #<FUNCTION 10+ (NUMBER) (DECLARE (SYSTEM::IN-DEFUN 10+)) >> > � � (BLOCK 10+ (+ 10 NUMBER))> >> [1i] CL-USER(4): (inspect #'foo) > > I tried that. Totally works, thanks... Notice that it the worst of the cases, you can do something like: (with-input-from-string (in (with-output-to-string (*standard-output*) (describe (function 10+)))) (read-char in) (read-char in) (read in) (read in) (read in)) --> (NUMBER) or something similar with INSPECT. The only caveat being that again, the parsing of the output of these function is implementation dependant. -- __Pascal Bourguignon__ |