Listcomprehension-macro? Macros with args inside macro-name?

This is a discussion on Listcomprehension-macro? Macros with args inside macro-name? within the lisp forums in Programming Languages category; On Sep 16, 10:38*pm, namekuseijin <namekusei...@gmail.com> wrote: > On Sep 16, 4:56*pm, "jos...@corporate-world.lisp.de" <jos...@corporate- .... > My main purpose was eliminating slow list processing from my coding, > relying primarily on the iterator-building range. *Thus, when I need > some specific order, I simply invert the terms to range. *I range over > vectors and strings as well. How do you know it was slow? A bunch of functions calling each other is not necessarily faster. In Common Lisp one gets rid of the intermediate lists by using LOOP/ITERATE/SERIES/.... and stays descriptive. > Though I also give small lists a ...

Go Back   Application Development Forum > Programming Languages > lisp

Object Mix

Register FAQ Calendar Search Today's Posts Mark Forums Read
  #21  
Old 09-16-2008, 05:51 PM
joswig@corporate-world.lisp.de
Guest
 
Default Re: Listcomprehension-macro? Macros with args inside macro-name?

On Sep 16, 10:38*pm, namekuseijin <namekusei...@gmail.com> wrote:
> On Sep 16, 4:56*pm, "jos...@corporate-world.lisp.de" <jos...@corporate-


....

> My main purpose was eliminating slow list processing from my coding,
> relying primarily on the iterator-building range. *Thus, when I need
> some specific order, I simply invert the terms to range. *I range over
> vectors and strings as well.


How do you know it was slow? A bunch of functions calling each other
is not necessarily faster.

In Common Lisp one gets rid of the intermediate lists
by using LOOP/ITERATE/SERIES/.... and stays descriptive.

> Though I also give small lists a chance by permitting them in the
> input. *Reversing the output list may be more efficient, since you're
> likely filtering elements out.
>
> > Personally I either use small functional building blocks
> > which do one thing: remove, reverse, map, reduce and so on
> > or I use something that is declarative like LOOP.

>
> > So either:

>
> > (mapcar #'sqr (remove-if-not (lambda (x) (> x 20)) '(12 31 2 33)))

>
> In that small list argument, it's not evident, but mapping over large
> sequences sucks. *That's one of the reasons I decided for range.


Really? Does it matter? Often?

> > (loop for i in '(12 31 2 33) when (> i 20) collect (sqr i))

>
> Then, what you do with the collected data? *Run some function over it
> to produce a final result, right?


Sometimes. Often not. Then I do something else.

> ((all sqr '(12 31 2 33) (lambda (x) (> x 20))) init function)
>
> Done, without producing intermediary lists or anything. *It's also
> almost the same written size as the macroed code above.


Yeah, but without any clue what the terms do and how it works.
Especially
a function that gets a function and returns a function and then gets
called
with another function. That's a rube-goldberg-device.

> > > and it can be used in a multitude of ways, not simply to return a
> > > list:

>
> > That makes it worse.

>
> This coming from a CLisper!
>
> > It should do one thing right or do
> > multiple things but be descriptive.

>
> ah, lack of keywords... no problem when the interface is always the
> same: *reducers are always of the form (lambda (i r) ...) where i is
> the current item from the iterator, r the current result and reducer
> itself produces the next result to be fed recursively.
>
> > * the user interface is confused and adhoc

>
> It's not adhoc, like I said above: *all and range return an iterator
> and receive 2 arguments -- an initial value for the reducer and the
> reducer. *That's all.


Yeah, and from reading source code using this constructs one
could not even guess what it does.

> It's always (iterator init f) and it's result is always passed around
> as the r argument and as the final value. *It's the same as fold/
> reduce, except for the lack of a sequence/list argument.
>
> You can also freely ignore the result, though, and then you have a
> simple imperative construct, like in the print example.
>
> > * the code is debugger-resistent

>
> There's nothing to debug there. *It's perfect!


I'm talking about code that uses such constructs. Bad. Very bad.

> > * code using that is not self-descriptive

>
> Hmm, perhaps you should break out of CL's loops and have a look at
> more applicative programming?


See below.

> > * there is no simple model behind it (say like streams in SICP)

>
> It looks pretty simple and consistent to me.


Reread the chapter on streams and accumulation in SICP.

> > You can make it worse, though. By rewriting it as a set of macros.

>
> Not rewriting a set of macros, but simply wrapping it behind a macro.
> Like:
> (all (sqr x) (x in (range 1 100)) (and (> x 20) (odd? x)))
>
> Which would equaly return an iterator.
>
> > From looking
> > at the forms I would never guess what it does.

>
> Probably you should give Scheme another chance.


Actually I have written much more complicated stuff in Scheme than
what you
have posted here. I prefer Common Lisp because it is much more
descriptive
and much better to use interactively.

> > > ((all sqr '(12 31 2 33) (lambda (x) (> x 20))) 0 +)
> > > ((all sqr '(12 31 2 33) (lambda (x) (and (> x 20) (odd? x))) 1 *)

>
> > > Order is not important in many applications.

>
> > Haha. Right, that's the Scheme way.

>
> That's functional programming way.


No, your code is the obfuscated way of functional programming.
Reread SICP to get back on the right way.


Reply With Quote
  #22  
Old 09-16-2008, 09:09 PM
namekuseijin
Guest
 
Default Re: Listcomprehension-macro? Macros with args inside macro-name?

On 16 set, 18:51, "jos...@corporate-world.lisp.de" <jos...@corporate-
world.lisp.de> wrote:
> On Sep 16, 10:38*pm, namekuseijin <namekusei...@gmail.com> wrote:
> > On Sep 16, 4:56*pm, "jos...@corporate-world.lisp.de" <jos...@corporate-

>
> > My main purpose was eliminating slow list processing from my coding,
> > relying primarily on the iterator-building range. *Thus, when I need
> > some specific order, I simply invert the terms to range. *I range over
> > vectors and strings as well.

>
> How do you know it was slow?


mapcar is not much used for serious large dataset prossessing. You
guys are known to abuse of loop.

> A bunch of functions calling each other
> is not necessarily faster.


It's really the application of just 2 function.

> In Common Lisp one gets rid of the intermediate lists
> by using LOOP/ITERATE/SERIES/.... and stays descriptive.


There's none of that in Scheme and even if had, I'd not use them any
more than I'd use C/C++...

Besides, is this
(all sqr '(12 31 2 33) (lambda (x) (> x 20)))

really so different from this?
[x**2 for x in [12,31,2,33] if x > 20]

In all, it takes 3 arguments: a final step function to process the
current item, a list or an iterator for a sequence and an optional
predicate. Is there really any complication here? Does it need more
description than the order and naming of the arguments? I
purposefully put the order of the arguments in the same order they
appear in the popular comprehensions in Haskell or Python exactly to
match them.

The only difference is that my function returns an iterator while the
Python one directly returns a list. I'd argue my function is better
since I can directly apply the resultant iterator to any function I
want together with its initial argument.

> > > (mapcar #'sqr (remove-if-not (lambda (x) (> x 20)) '(12 31 2 33)))

>
> > In that small list argument, it's not evident, but mapping over large
> > sequences sucks. *That's one of the reasons I decided for range.

>
> Really? Does it matter? Often?


Only when iterating large data sets.

> > > (loop for i in '(12 31 2 33) when (> i 20) collect (sqr i))

>
> > Then, what you do with the collected data? *Run some function over it
> > to produce a final result, right?

>
> Sometimes. Often not. Then I do something else.


Like printing it?
((all sqr (range 1 10000) (lambda (x) (prime? x))) #f
(lambda (i r) (display i)(newline) r))
Passing it to another function?
((all sqr (range 1 10000) (lambda (x) (prime? x))) init something-
else)

Perhaps you're just mad because it makes Lisp look a bit like
Forth?

> > Done, without producing intermediary lists or anything. *It's also
> > almost the same written size as the macroed code above.

>
> Yeah, but without any clue what the terms do and how it works.


I can't use any one function without knowing its arguments, its
interface. Its the contract between the creator and the user. The
interface for my function is pretty simple, self-evident and pretty
much the same as in the other popular comprehensions of other
languages.

There should also be no doubt for a Lisp programmer: anything at the
head position of a list is a function to be evaluated. So (all self
ls) should necessarily return a function. It shouldn't also come as
surprise to most functional programmers used to fold.

> Especially
> a function that gets a function and returns a function and then gets
> called
> with another function. That's a rube-goldberg-device.


No, that's functional programming.

> > It's not adhoc, like I said above: *all and range return an iterator
> > and receive 2 arguments -- an initial value for the reducer and the
> > reducer. *That's all.

>
> Yeah, and from reading source code using this constructs one
> could not even guess what it does.


Then again, why am I discussing code from my personal libs with you?
It fits my thinking and I feel warm and cosy with that.

> Reread the chapter on streams and accumulation in SICP.


SICP is a lovely book, but I have my own way of doing things, like
everyone else. There are many stream and even comprehension libs
available for Scheme out there, including the ones from SRFI. I just
find mine more sexy.

> No, your code is the obfuscated way of functional programming.


I like to call it myscm.

I thought one of the professed pro-Lisp arguments is that it's a
language that suits to your style of programming, not otherwise. So
please, don't laugh at my preferences...

> Reread SICP to get back on the right way.


Just because I read Shakespeare I don't feel a sudden urge to speak in
old English... :P
Reply With Quote
  #23  
Old 09-19-2008, 03:06 AM
André Thieme
Guest
 
Default Re: Listcomprehension-macro? Macros with args inside macro-name?

William James schrieb:
> On Aug 22, 5:47 pm, David Golden <david.gol...@oceanfree.net> wrote:
>> defn noob wrote:
>>> I am trying to learn lisp macros and I generally find
>>> listcomprehensions to be elegant and they dont exist in lisp.
>>> This has to be a macro right? Cant be a function?

>> You might want to look at the COLLECT macrohttp://user.it.uu.se/~svenolof/Collect/
>>
>>> [x**2 for x in [12,31,2,33] if x > 20]
>>> [961, 1089]

>> (collect list ((expt x 2)) (in x '(12 31 2 33)) (when (> x 20)))
>> => (961 1089)

>
> Ruby:
> [12,31,2,33].select{|n| n>20}.map{|n| n**2}
> ==>[961, 1089]


Yes, also in Ruby one can have a nice solution as you showed.
But still, the Lisp solution shown is the preferrable one, because it
is the shorter program. Not character wise. But that doesn’t count.
If the function is called slct or select or if it had a 14-char name,
it won’t matter. It’s all just one point in the program, and therewith
a complexity unit.

The Lisp code has these:
collect, list, (), expt, x, 2, in, x, ', (), 12, 31, 2, 33, when, >, x, 20
That gives us 18 points.

But your Ruby code has 19:
[], 12, 31, 2, 33, select, {}, ||, n, n, >, 20, map, {}, ||, n, n, **, 2

Lisp wins, although this time only by a small margin, compared to your
other examples which often be solved only in a noticable more complex
way than in Lisp.

Please don’t forget that advances in programming languages
should help us to remove complexity and make things easier.


If you wanted you could do exactly the same thing in Lisp as in
[12, 31, 2, 33].select{|n| n>20}.map{|n| n**2}

like this:
(mapcar (lambda (n) (expt n 2))
(select '(12 31 2 33)
(lambda (n) (< n 20))))

Because Lisp uses lengthier names the solution looks longer when counting
chars. But algorithmically it is the same.
If you had to write tons of such small functions you would introduce a
macro and do:
(map [ˆ2] (select '(12 31 2 33) [< _ 20]))

Here we renamed functions to reflect the preferrence of short names.
We have the function ˆ2 which squares its argument. We curry away the
variable and introduce anonymous currying for the lambda to select.
Think about how you can add implicit currying to Ruby without touching
the C code which it is implemented in, but instead doing it with a pure
Ruby solution.


André
--
Reply With Quote
Reply


Thread Tools
Display Modes


All times are GMT -5. The time now is 11:46 PM.


Powered by vBulletin® Version 3.7.2
Copyright ©2000 - 2009, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.2.0
vB Ad Management by =RedTyger=

In an effort to better serve ads to our visitors, cookies are used on objectmix.com. For more information, check out our Privacy Policy.