From: ·······@eurogaran.com
Subject: about pushnew
Date: 
Message-ID: <0a00f798-c7fd-4fb8-a5e1-37c84702c53e@r15g2000prh.googlegroups.com>
Let's create an empty list, for instance with (setq list ())
Now suppose I want to push a number into it only if said number is not
3.
The following code seems reasonable:
(pushnew number list :test #'(lambda (a b) (= 3 a)))
...and in fact works... BUT ONLY WHEN list IS NOT EMPTY!
In other words: the first element is always pushed onto list by
pushnew, regardless of :test.
This is the behavior in all the implementations I have tested.
1) Is it conformat?
2) Is it desireable?
3) Ideas on how to circumvent it?

From: Marco Antoniotti
Subject: Re: about pushnew
Date: 
Message-ID: <58cd8721-c65a-4773-b9ec-2172b711f5b8@f40g2000pri.googlegroups.com>
On Feb 3, 7:22 pm, ·······@eurogaran.com wrote:
> Let's create an empty list, for instance with (setq list ())
> Now suppose I want to push a number into it only if said number is not
> 3.
> The following code seems reasonable:
> (pushnew number list :test #'(lambda (a b) (= 3 a)))
> ...and in fact works... BUT ONLY WHEN list IS NOT EMPTY!
> In other words: the first element is always pushed onto list by
> pushnew, regardless of :test.

PUSHNEW pushes an item in the "stack" if the item is not there yet
(and the :TEST checks for that).   If the "stack" is empty, then the
item is obviously not there.  Hence it is pushed in.  Besides, the
test you pass requires two arguments: if the list is empty where does
the second argument come from?


> This is the behavior in all the implementations I have tested.
> 1) Is it conformat?

Yes.

> 2) Is it desireable?

Yes.

> 3) Ideas on how to circumvent it?

     (unless (= number 3) (push number list))

Cheers
--
Marco
From: Alex Mizrahi
Subject: Re: about pushnew
Date: 
Message-ID: <49888d48$0$90264$14726298@news.sunsite.dk>
 k> Now suppose I want to push a number into it only if said number is not
 k> 3.

(unless (= number 3) (push number list))

is it that hard?

 k> The following code seems reasonable:
 k> (pushnew number list :test #'(lambda (a b) (= 3 a)))

no, it does not. it looks like an idiotic hack.
test is meant to compare two items to check if they are same.

 k> ...and in fact works... BUT ONLY WHEN list IS NOT EMPTY!

yeah, that's a difference between hacks and adequate solutions
 -- adequate solutions work in all circumstances, hacks work
only in some.

 k> In other words: the first element is always pushed onto list by
 k> pushnew,  regardless of :test.

yep, by definition of pushnew it pushes element if it is not present
in list already. no element can be present in an empty list, thus
first element is always "new" and is always pushed.

i really wonder how do you think it could work, should it pass NIL
as b to your function or what?

 k>  This is the behavior in all the implementations I have tested.
 k> 1) Is it conformat?

i'm pretty sure that if it would work in your way it would not be
conformant, because NIL is not element of ().

 k> 2) Is it desireable?

that's how it should work. i dunno if it is desireable or not.

 k> 3) Ideas on how to circumvent it?

are you trying to circument normal rules of logic? 
From: ·······@eurogaran.com
Subject: Re: about pushnew
Date: 
Message-ID: <b026cacf-b728-4dcb-be69-5930750c94fa@p23g2000prp.googlegroups.com>
On Feb 3, 7:30 pm, "Alex Mizrahi" <········@users.sourceforge.net>
wrote:
> (unless (= number 3) (push number list))
> is it that hard?

No. It is trivial, but keep in mind the title of my post was "about
pushnew".

>  k> The following code seems reasonable:
>  k> (pushnew number list :test #'(lambda (a b) (= 3 a)))
>
> no, it does not. it looks like an idiotic hack.

Indeed; except if substituting number we had
(some_S-expression_that_returns_a_number)
in which case it does not look so idiotic.

> test is meant to compare two items to check if they are same.
Now you are touching on matter.
It can be argued that any function that has 2 arguments
is a function of 2 arguments, inspite if it only uses one of them.

>  k> ...and in fact works... BUT ONLY WHEN list IS NOT EMPTY!
>
> yeah, that's a difference between hacks and adequate solutions
>  -- adequate solutions work in all circumstances, hacks work
> only in some.
I agree. My objective was only to pose an example as clear and simple
as possible, not that it had any practical use.

>  k> In other words: the first element is always pushed onto list by
>  k> pushnew,  regardless of :test.
>
> yep, by definition of pushnew it pushes element if it is not present
> in list already. no element can be present in an empty list, thus
> first element is always "new" and is always pushed.
>
> i really wonder how do you think it could work, should it pass NIL
> as b to your function or what?
>
>  k>  This is the behavior in all the implementations I have tested.
>  k> 1) Is it conformat?
>
> i'm pretty sure that if it would work in your way it would not be
> conformant, because NIL is not element of ().

Well, that remains debatable, since both (car ()) and (cdr ()) return
nil

>  k> 2) Is it desireable?
>
> that's how it should work. i dunno if it is desireable or not.

I am looking for opinions on this second point. Thanks for yours.

>  k> 3) Ideas on how to circumvent it?
> are you trying to circument normal rules of logic?
Not at all.
From: ·······@eurogaran.com
Subject: Re: about pushnew
Date: 
Message-ID: <b5b9900b-a6c5-4088-a68d-54636e1c3cd9@x6g2000pre.googlegroups.com>
> It can be argued that any function that has 2 arguments
> is a function of 2 arguments, inspite if it only uses one of them.
The function could even "decide" to use (or not) the second argument
based on the value of the first one, or the time of day...

My opinion here is that the specification should not enforce :test to
be an operator with 2 arguments.
From: Thomas A. Russ
Subject: Re: about pushnew
Date: 
Message-ID: <ymi7i47lz7x.fsf@blackcat.isi.edu>
·······@eurogaran.com writes:

> > It can be argued that any function that has 2 arguments
> > is a function of 2 arguments, inspite if it only uses one of them.
> The function could even "decide" to use (or not) the second argument
> based on the value of the first one, or the time of day...
> 
> My opinion here is that the specification should not enforce :test to
> be an operator with 2 arguments.

Of course is should enforce it.

First of all, programmers need to know what sort of function is a legal
value to TEST.

Second, the implementers have to know how to call the TEST function, and
it's really hard to write a routine that invokes a function with an
unknown number of arguments.

Third, it's hard to imagine how the ANSI specification could be any more
explicit than what it currently says about the arguments to PUSHNEW:

   "test---a designator for a function of two arguments that returns a
           generalized boolean."

That clearly states the test must be a function of two arguments.



-- 
Thomas A. Russ,  USC/Information Sciences Institute
From: Pascal Costanza
Subject: Re: about pushnew
Date: 
Message-ID: <6us2l8Fgql1bU1@mid.individual.net>
·······@eurogaran.com wrote:
>> It can be argued that any function that has 2 arguments
>> is a function of 2 arguments, inspite if it only uses one of them.
> The function could even "decide" to use (or not) the second argument
> based on the value of the first one, or the time of day...
> 
> My opinion here is that the specification should not enforce :test to
> be an operator with 2 arguments.

You're confused. The reason why pushnew behaves the way it does is not 
because of the test function. It behaves the way it does because the 
specification clearly says what it's intended purpose is.

To cite: "pushnew tests whether item is the same as any existing element 
of the list stored in place. If item is not, it is prepended to the 
list, and the new list is stored in place."

If the list stored in the given place is empty, there is no existing 
element, so the item cannot be the same as any of those non-existing 
elements by definition.

You want a different kind of functionality than that specified for 
pushnew, so you should better use a different function or macro. It 
would be a horrible idea to turn pushnew into behaving completely 
differently because of a test function with some arbitrary behavior.

Here is a thought experiment for you: Assume the list is empty, how 
often do you want the test function to be called? With what arguments? 
Assume the list has exactly one element, how often do you then want the 
test function to be called? With what arguments? Is it the same number? 
Is it a different number? How can the test function distinguish those 
two cases?


Pascal

-- 
ELS'09: http://www.european-lisp-symposium.org/
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: William James
Subject: Re: about pushnew
Date: 
Message-ID: <gmamus0kjt@enews4.newsguy.com>
Pascal Costanza wrote:

> ·······@eurogaran.com wrote:
> > > It can be argued that any function that has 2 arguments
> > > is a function of 2 arguments, inspite if it only uses one of them.
> > The function could even "decide" to use (or not) the second argument
> > based on the value of the first one, or the time of day...
> > 
> > My opinion here is that the specification should not enforce :test
> > to be an operator with 2 arguments.
> 
> You're confused. The reason why pushnew behaves the way it does is
> not because of the test function. It behaves the way it does because
> the specification clearly says what it's intended purpose is.
> 
> To cite: "pushnew tests whether item is the same as any existing
> element of the list stored in place. If item is not, it is prepended
> to the list, and the new list is stored in place."
> 
> If the list stored in the given place is empty, there is no existing
> element, so the item cannot be the same as any of those non-existing
> elements by definition.
> 
> You want a different kind of functionality than that specified for
> pushnew, so you should better use a different function or macro. It
> would be a horrible idea to turn pushnew into behaving completely
> differently because of a test function with some arbitrary behavior.
> 
> Here is a thought experiment for you: Assume the list is empty, how
> often do you want the test function to be called? With what
> arguments? Assume the list has exactly one element, how often do you
> then want the test function to be called? With what arguments? Is it
> the same number? Is it a different number? How can the test function
> distinguish those two cases?
> 
> 
> Pascal

Ruby:


def pushnew x, list, &block
  print "pushnew:"
  block ||= proc{|a,b| a==b}
  list.unshift x unless list.any?{|y| print " #{y}"
    block.call(x,y) }
  puts
  list
end

mylist = []

pushnew 12, mylist
pushnew 8, mylist
pushnew 8, mylist
pushnew 4, mylist
pushnew( 3, mylist){|a,b|  a%3 == b%3 }

p mylist

--- output ---
pushnew:
pushnew: 12
pushnew: 8
pushnew: 8 12
pushnew: 4 8 12
[4, 8, 12]
From: Kenneth Tilton
Subject: Re: about pushnew
Date: 
Message-ID: <4988fbe8$0$7756$607ed4bc@cv.net>
William James wrote:
> Pascal Costanza wrote:
> 
>> ·······@eurogaran.com wrote:
>>>> It can be argued that any function that has 2 arguments
>>>> is a function of 2 arguments, inspite if it only uses one of them.
>>> The function could even "decide" to use (or not) the second argument
>>> based on the value of the first one, or the time of day...
>>>
>>> My opinion here is that the specification should not enforce :test
>>> to be an operator with 2 arguments.
>> You're confused. The reason why pushnew behaves the way it does is
>> not because of the test function. It behaves the way it does because
>> the specification clearly says what it's intended purpose is.
>>
>> To cite: "pushnew tests whether item is the same as any existing
>> element of the list stored in place. If item is not, it is prepended
>> to the list, and the new list is stored in place."
>>
>> If the list stored in the given place is empty, there is no existing
>> element, so the item cannot be the same as any of those non-existing
>> elements by definition.
>>
>> You want a different kind of functionality than that specified for
>> pushnew, so you should better use a different function or macro. It
>> would be a horrible idea to turn pushnew into behaving completely
>> differently because of a test function with some arbitrary behavior.
>>
>> Here is a thought experiment for you: Assume the list is empty, how
>> often do you want the test function to be called? With what
>> arguments? Assume the list has exactly one element, how often do you
>> then want the test function to be called? With what arguments? Is it
>> the same number? Is it a different number? How can the test function
>> distinguish those two cases?
>>
>>
>> Pascal
> 
> Ruby:
> 
> 
> def pushnew x, list, &block
>   print "pushnew:"
>   block ||= proc{|a,b| a==b}
>   list.unshift x unless list.any?{|y| print " #{y}"
>     block.call(x,y) }
>   puts
>   list
> end
> 
> mylist = []
> 
> pushnew 12, mylist
> pushnew 8, mylist
> pushnew 8, mylist
> pushnew 4, mylist
> pushnew( 3, mylist){|a,b|  a%3 == b%3 }
> 
> p mylist
> 
> --- output ---
> pushnew:
> pushnew: 12
> pushnew: 8
> pushnew: 8 12
> pushnew: 4 8 12
> [4, 8, 12]


You remind me of a penguin who sees Arctic gulls walking awkwardly to 
get ten feet or going thru a whole take-off and landing and says, Hey 
dummies, you can't do this? before throwing himself on his belly and 
sliding ten feet.

hth,kth
From: Scott
Subject: Re: about pushnew
Date: 
Message-ID: <4ae611f4-2efd-4d41-81ea-746bddae984e@m22g2000vbp.googlegroups.com>
On Feb 3, 7:22 pm, Kenneth Tilton <·········@gmail.com> wrote:
> William James wrote:
>
> > Ruby:
>
> > def pushnew x, list, &block
> >   print "pushnew:"
> >   block ||= proc{|a,b| a==b}
> >   list.unshift x unless list.any?{|y| print " #{y}"
> >     block.call(x,y) }
> >   puts
> >   list
> > end
>
> You remind me of a penguin who sees Arctic gulls walking awkwardly to
> get ten feet or going thru a whole take-off and landing and says, Hey
> dummies, you can't do this? before throwing himself on his belly and
> sliding ten feet.
>

Of the several folks who keep picking fights with you Common Lispers,
I like the Ruby guy best.  He posts short, presumably working, code
and quietly goes away.  He's out-smugging you.
From: Kenneth Tilton
Subject: Re: about pushnew
Date: 
Message-ID: <49892368$0$24992$607ed4bc@cv.net>
Scott wrote:
> On Feb 3, 7:22 pm, Kenneth Tilton <·········@gmail.com> wrote:
>> William James wrote:
>>
>>> Ruby:
>>> def pushnew x, list, &block
>>>   print "pushnew:"
>>>   block ||= proc{|a,b| a==b}
>>>   list.unshift x unless list.any?{|y| print " #{y}"
>>>     block.call(x,y) }
>>>   puts
>>>   list
>>> end
>> You remind me of a penguin who sees Arctic gulls walking awkwardly to
>> get ten feet or going thru a whole take-off and landing and says, Hey
>> dummies, you can't do this? before throwing himself on his belly and
>> sliding ten feet.
>>
> 
> Of the several folks who keep picking fights with you Common Lispers,
> I like the Ruby guy best.  He posts short, presumably working, code
> and quietly goes away.  He's out-smugging you.
> 

Don't get me wrong: that belly sliding looks like a ball!*

hth,kth

* Offered in confidence that this will do no damage to the thick skull 
protecting Scotty's hypothesized brain. k
From: Raffael Cavallaro
Subject: Re: about pushnew
Date: 
Message-ID: <gmdan2$7lu$1@aioe.org>
On 2009-02-03 23:49:02 -0500, Scott <·······@gmail.com> said:

> He posts short, presumably working, code
> and quietly goes away.

Only for those selected toy tasks for which he can provide ruby 
equivalents, which means he only posts to threads where simple tasks 
are explained - how unimpressive. Check out the newlisp macro thread 
where Marco Antoniotti challenged him to provide a ruby version. We're 
still waiting for it...

It's easy to be smug if one is permitted to provide only a proper 
subset of lisp's functionality.



-- 
Raffael Cavallaro, Ph.D.
From: Scott
Subject: Re: about pushnew
Date: 
Message-ID: <21eb1928-8004-4cda-9303-011a87afe252@x38g2000yqj.googlegroups.com>
On Feb 4, 5:09 pm, Raffael Cavallaro
<················@pas.espam.s.il.vous.plait.mac.com> wrote:
> On 2009-02-03 23:49:02 -0500, Scott <·······@gmail.com> said:
>
> > He posts short, presumably working, code
> > and quietly goes away.
>
> Only for those selected toy tasks for which he can provide ruby
> equivalents, which means he only posts to threads where simple tasks
> are explained - how unimpressive. Check out the newlisp macro thread
> where Marco Antoniotti challenged him to provide a ruby version. We're
> still waiting for it...
>

I've honestly never written a single line of Ruby before 20 minutes
ago.  But given that Ruby apparently doesn't have macros (or the pass
by list to be evaluated in a dynamic context thing in newLisp), I
think the following is pretty close in spirit:

def atleastn(n, *args)
    count = 0
    args.each { |arg| if arg.call(): count += 1 end }
    return count >= n
end

# usage:
print atleastn(2,
  lambda { 1 == 1 },
  lambda { 3 == 2 },
  lambda { 2 == 5 },
  lambda { 2 == 20 }
), "\n";

I honestly don't know if there is a better way in Ruby, but that would
get the job done, and maybe the Ruby guy will chime in and improve it.
From: Marco Antoniotti
Subject: Re: about pushnew
Date: 
Message-ID: <e6038602-a864-4f2f-a20e-e2c2502482ca@v5g2000prm.googlegroups.com>
On Feb 5, 5:57 am, Scott <·······@gmail.com> wrote:
> On Feb 4, 5:09 pm, Raffael Cavallaro
>
> <················@pas.espam.s.il.vous.plait.mac.com> wrote:
> > On 2009-02-03 23:49:02 -0500, Scott <·······@gmail.com> said:
>
> > > He posts short, presumably working, code
> > > and quietly goes away.
>
> > Only for those selected toy tasks for which he can provide ruby
> > equivalents, which means he only posts to threads where simple tasks
> > are explained - how unimpressive. Check out the newlisp macro thread
> > where Marco Antoniotti challenged him to provide a ruby version. We're
> > still waiting for it...
>
> I've honestly never written a single line of Ruby before 20 minutes
> ago.  But given that Ruby apparently doesn't have macros (or the pass
> by list to be evaluated in a dynamic context thing in newLisp), I
> think the following is pretty close in spirit:
>
> def atleastn(n, *args)
>     count = 0
>     args.each { |arg| if arg.call(): count += 1 end }
>     return count >= n
> end
>
> # usage:
> print atleastn(2,
>   lambda { 1 == 1 },
>   lambda { 3 == 2 },
>   lambda { 2 == 5 },
>   lambda { 2 == 20 }
> ), "\n";
>
> I honestly don't know if there is a better way in Ruby, but that would
> get the job done, and maybe the Ruby guy will chime in and improve it.

If you are trying to match my (c)lazy trick, you are still missing
something.
I did not pass lambdas to my call.  The call to my AT-LEAST-N thingy
can be:

cl-prompt> (at-least-n 2
                       (= (+ 40 2) 42)
                       (= (+ 2 2) 5)
                       (zerop 0)
                       (computing-the-answer-for-a-very-long-time-
yielding-42)
                       nil)
T ; after a very short time, since I can compile my stuff: Ruby can't.

Look ma!  No lambdas! (They are there, but you don't have to see
them).
So, the (c)lazy solution encompasses clearly and cleanly newLisp
solution and your Ruby one (or the yet-to-be-seen Ruby guy's one).
BTW.  Your Ruby solution in CL can be written as

(defun at-least-n (n &rest thunks) ; Let's call them with their usual
name.
  (loop for thunk in thunks
        when (funcall thunk) sum 1 into count
        when (>= count n) return t))

or

(defun at-least-n (n &rest thunks) ; Just showing off :)
   (cond ((null thunks) nil)
         ((plusp n)
          (let ((more-thunks (member t thunks
                                     :key (compose 'not 'null
'funcall))))
             ;; I love MEMBER returning the sublist.
             (when more-thunks
                 (apply 'at-least-n (1- n) (rest more-thunks)))))
         (t t)))


Which work (both versions) also as

(at-least-n 2 (lambda () t) (lambda () nil) (lambda () t) (lambda ()
(loop)))

In any case I upped the ante: write the equivalent of (c)lazy in Ruby
and show that the code you write in the body of your lazy "blocks" can
be as clean as the CL one.  No googling showed anything similar in
Ruby. :)  Other languages (e.g., Haskell) have it built in.  But the
point of CLAZY is that you *can* write that in CL in a very easy way;
easier than AFAIAC in any other language I know.  YMMV etc etc. :)

Cheers
--
Marco
www.european-lisp-symposium.org
From: Raffael Cavallaro
Subject: Re: about pushnew
Date: 
Message-ID: <gmfr85$amp$1@aioe.org>
On 2009-02-04 23:57:03 -0500, Scott <·······@gmail.com> said:

> I've honestly never written a single line of Ruby before 20 minutes
> ago.  But given that Ruby apparently doesn't have macros (or the pass
> by list to be evaluated in a dynamic context thing in newLisp), I
> think the following is pretty close in spirit:
> 
> def atleastn(n, *args)
>     count = 0
>     args.each { |arg| if arg.call(): count += 1 end }
>     return count >= n
> end

Doesn't this evaluate all of the args? The whole point of the macro (in 
both lisp and newlisp) is that it short circuits evaluation once the 
specified number of true args are evaluated (which also means it 
doesn't evaluate *any* args if n is 0). So this does not do what the 
macro does:

rafbookpro:~ raffaelc$ irb
>> y = 10
=> 10
>> y
=> 10
>> def atleastn(n, *args)
>>     count = 0
>>     args.each { |arg| if arg.call(): count += 1 end }
>>     return count >= n
>> end
=> nil
>> print atleastn(0, lambda { y = y + 1})
true=> nil
>> y
=> 11
>>


-- 
Raffael Cavallaro, Ph.D.
From: Scott
Subject: Re: about pushnew
Date: 
Message-ID: <d1ef0075-343c-43cd-a6b1-4c60eb05c966@w1g2000prm.googlegroups.com>
On Feb 5, 4:03 pm, Raffael Cavallaro
<················@pas.espam.s.il.vous.plait.mac.com> wrote:
> On 2009-02-04 23:57:03 -0500, Scott <·······@gmail.com> said:
>
> > def atleastn(n, *args)
> >     count = 0
> >     args.each { |arg| if arg.call(): count += 1 end }
> >     return count >= n
> > end
>
> Doesn't this evaluate all of the args? The whole point of the macro (in
> both lisp and newlisp) is that it short circuits evaluation once the
> specified number of true args are evaluated (which also means it
> doesn't evaluate *any* args if n is 0). So this does not do what the
> macro does:
>

I should know better than to get sucked into these things.  I was just
trying to poke kenny in the ribs while simultaneously encouraging the
Ruby guy (I prefer his kind of audacity to the other obnoxious trolls
here)...

The first macro I saw, which I assumed was the one you were talking
about, was:

    (define-macro (at-least-two)
              (let (c)
                   (doargs (i (= c 2))
                           (if (eval i)
                               (inc c)))
                   (>= c 2)))

I only skimmed the thread before, but it looks like you guys got more
specific about the laziness of it as the discussion went on.  Ok fine,
here's twenty more minutes (and some abuse of the ternary operator):

def atleastn(n, *thunks)
    return n <= 0 ? true :
       thunks.empty? ? false :
       atleastn(thunks[0].call ? n - 1 : n, *thunks[1..-1])
end

# usage:
print atleastn(2,
    lambda { 1 == 1 },
    lambda { 3 == 2 },
    lambda { 5 == 5 },
    lambda { print "won't get here\n"; return 3 == 20 }
), "\n";


I'll certainly admit it's not *as* clean because of the lambdas, and I
don't really care to defend Ruby anymore, but it's silly to claim this
sort of thing is only easily solvable in Common Lisp.  Your loop
version is aesthetically pleasing enough, but the second "showing off"
version is ugly.
From: Kenneth Tilton
Subject: Re: about pushnew
Date: 
Message-ID: <498bdc3b$0$32265$607ed4bc@cv.net>
Scott wrote:
> On Feb 5, 4:03 pm, Raffael Cavallaro
> <················@pas.espam.s.il.vous.plait.mac.com> wrote:
>> On 2009-02-04 23:57:03 -0500, Scott <·······@gmail.com> said:
>>
>>> def atleastn(n, *args)
>>>     count = 0
>>>     args.each { |arg| if arg.call(): count += 1 end }
>>>     return count >= n
>>> end
>> Doesn't this evaluate all of the args? The whole point of the macro (in
>> both lisp and newlisp) is that it short circuits evaluation once the
>> specified number of true args are evaluated (which also means it
>> doesn't evaluate *any* args if n is 0). So this does not do what the
>> macro does:
>>
> 
> I should know better than to get sucked into these things.  I was just
> trying to poke kenny in the ribs...

Your life may need loftier goals.

hth,kth
From: Marco Antoniotti
Subject: Re: about pushnew
Date: 
Message-ID: <9692b959-fea0-49df-887e-d544a543cba1@b38g2000prf.googlegroups.com>
On Feb 6, 4:45 am, Scott <·······@gmail.com> wrote:
> On Feb 5, 4:03 pm, Raffael Cavallaro
>
> <················@pas.espam.s.il.vous.plait.mac.com> wrote:
> > On 2009-02-04 23:57:03 -0500, Scott <·······@gmail.com> said:
>
> > > def atleastn(n, *args)
> > >     count = 0
> > >     args.each { |arg| if arg.call(): count += 1 end }
> > >     return count >= n
> > > end
>
> > Doesn't this evaluate all of the args? The whole point of the macro (in
> > both lisp and newlisp) is that it short circuits evaluation once the
> > specified number of true args are evaluated (which also means it
> > doesn't evaluate *any* args if n is 0). So this does not do what the
> > macro does:
>
> I should know better than to get sucked into these things.  I was just
> trying to poke kenny in the ribs while simultaneously encouraging the
> Ruby guy (I prefer his kind of audacity to the other obnoxious trolls
> here)...
>
> The first macro I saw, which I assumed was the one you were talking
> about, was:
>
>     (define-macro (at-least-two)
>               (let (c)
>                    (doargs (i (= c 2))
>                            (if (eval i)
>                                (inc c)))
>                    (>= c 2)))
>
> I only skimmed the thread before, but it looks like you guys got more
> specific about the laziness of it as the discussion went on.  Ok fine,
> here's twenty more minutes (and some abuse of the ternary operator):
>
> def atleastn(n, *thunks)
>     return n <= 0 ? true :
>        thunks.empty? ? false :
>        atleastn(thunks[0].call ? n - 1 : n, *thunks[1..-1])
> end
>
> # usage:
> print atleastn(2,
>     lambda { 1 == 1 },
>     lambda { 3 == 2 },
>     lambda { 5 == 5 },
>     lambda { print "won't get here\n"; return 3 == 20 }
> ), "\n";
>
> I'll certainly admit it's not *as* clean because of the lambdas, and I
> don't really care to defend Ruby anymore, but it's silly to claim this
> sort of thing is only easily solvable in Common Lisp.  Your loop
> version is aesthetically pleasing enough, but the second "showing off"
> version is ugly.

Well, obviously the "showing off" one is just ... a show off.  AFAIAC,
your last Ruby version is uglier than your first as well.  But that is
not the point.

As you may have noticed, while your Ruby versions are legit, the "Ruby
Guy" is not trolling on this one.  And, I'd bet, the reason is that
you cannot do in Ruby (or in newLisp) what I did with CLAZY (at least
AFAIK). You must really really get under the hood to the
implementation level changing the actual evaluation rules to achieve
the same effects (plus you don't have macros and symbol-macros).
CLAZY is 100% ANSI Common Lisp.

Cheers
--
Marco
From: Scott
Subject: Re: about pushnew
Date: 
Message-ID: <c346c4b4-417d-4bef-a01d-6b20a1847478@i20g2000prf.googlegroups.com>
On Feb 6, 7:12 am, Marco Antoniotti <·······@gmail.com> wrote:
>
> As you may have noticed, while your Ruby versions are legit, the "Ruby
> Guy" is not trolling on this one.  And, I'd bet, the reason is that
> you cannot do in Ruby (or in newLisp) what I did with CLAZY (at least
> AFAIK). You must really really get under the hood to the
> implementation level changing the actual evaluation rules to achieve
> the same effects (plus you don't have macros and symbol-macros).
> CLAZY is 100% ANSI Common Lisp.
>

Nope, I seem to be the only troll in this thread.  I saw a couple of
other messages from the Ruby guy, and it looks like he's spitting
venom instead of posting smug little snippits of code.  Sigh - so much
for the high road.
From: Raffael Cavallaro
Subject: Re: about pushnew
Date: 
Message-ID: <gmhsob$cn$1@aioe.org>
On 2009-02-05 22:45:54 -0500, Scott <·······@gmail.com> said:

> I only skimmed the thread before, but it looks like you guys got more
> specific about the laziness of it as the discussion went on.  Ok fine,
> here's twenty more minutes (and some abuse of the ternary operator):
> 
> def atleastn(n, *thunks)
>     return n <= 0 ? true :
>        thunks.empty? ? false :
>        atleastn(thunks[0].call ? n - 1 : n, *thunks[1..-1])
> end
> 
> # usage:
> print atleastn(2,
>     lambda { 1 == 1 },
>     lambda { 3 == 2 },
>     lambda { 5 == 5 },
>     lambda { print "won't get here\n"; return 3 == 20 }
> ), "\n";

This misses the point of macros which is to change the language's 
evaluation syntax. If you're required to wrap every expression in a 
lambda you're not doing this. The reason your ruby version is "not *as* 
clean because of the lambdas" is because you have no tools in the 
language to change evaluation syntax.

You *must* pass the ruby version lambdas rather than ordinary 
expressions (e.g., (y = y + 1)) or it will both error, *and * evaluate 
all the args:

rafbookpro:~ raffaelc$ irb
>> def atleastn(n, *thunks)
>>     return n <= 0 ? true :
?>        thunks.empty? ? false :
?>        atleastn(thunks[0].call ? n - 1 : n, *thunks[1..-1])
>> end
=> nil
>> y = 0
=> 0
>> print atleastn(1, (y = y + 1), (y = y + 5))
NoMethodError: undefined method `call' for 1:Fixnum
	from (irb):4:in `atleastn'
	from (irb):7
>> y
=> 6
>>




-- 
Raffael Cavallaro, Ph.D.
From: William James
Subject: Re: about pushnew
Date: 
Message-ID: <gnqrbu0s6s@enews4.newsguy.com>
William James wrote:

> Ruby:
> 
> 
> def pushnew x, list, &block
>   print "pushnew:"
>   block ||= proc{|a,b| a==b}
>   list.unshift x unless list.any?{|y| print " #{y}"
>     block.call(x,y) }
>   puts
>   list
> end

Clojure:

(defn pushnew [x lst & proc]
  (let [proc (or (first proc) =)]
    (if (not-any? #(proc % x) lst)
      (cons x lst)
      lst)))
 
From: André Thieme
Subject: Re: about pushnew
Date: 
Message-ID: <gns34g$bu5$1@news.motzarella.org>
William James schrieb:
> William James wrote:
> 
>> Ruby:
>>
>>
>> def pushnew x, list, &block
>>   print "pushnew:"
>>   block ||= proc{|a,b| a==b}
>>   list.unshift x unless list.any?{|y| print " #{y}"
>>     block.call(x,y) }
>>   puts
>>   list
>> end
> 
> Clojure:
> 
> (defn pushnew [x lst & proc]
>   (let [proc (or (first proc) =)]
>     (if (not-any? #(proc % x) lst)
>       (cons x lst)
>       lst)))
>  

It�s good.
Funny that I have to say this :)

For overloading the function to work on different arities you could also
do this:

(defn pushnew
   "Documentation, available via (doc pushnew)"
   ([x coll] (pushnew x list =))
   ([x coll f] (if (not-any? #(f % x) coll)
                   (conj coll x)
                   coll)))

So, defn takes the name, pushnew here.
It optionally takes a doc string.
And then some lists follow, which should have the parameter vector as
their first argument, and then the body.
Also instead of cons I suggest to use conj.
Now that same function also works for vectors. And Hashmaps. And Sets.
And structure hashmaps. And TreeMaps.

(pushnew 15 '(10 20 30)) ==> (15 10 20 30)
(pushnew 15 [10 20 30])  ==> [10 20 30 15]
(pushnew {:c 30} {:a 10, :b 20}) ==> {:a 10, :b 20, :c 30}
(pushnew 7 #{10 20 30} <) ==> #{7 10 20 30}

The comma btw is whitespace, such as tab, \n or a space.
I used it for nicer readability.


Andr�
-- 
Lisp is not dead. It�s just the URL that has changed:
http://clojure.org/
From: William James
Subject: Re: about pushnew
Date: 
Message-ID: <gnsdbi01ut1@enews2.newsguy.com>
Andr� Thieme wrote:

> For overloading the function to work on different arities you could
> also do this:
> 
> (defn pushnew
>   "Documentation, available via (doc pushnew)"
>   ([x coll] (pushnew x list =))
>   ([x coll f] (if (not-any? #(f % x) coll)
>                   (conj coll x)
>                   coll)))
> 
> So, defn takes the name, pushnew here.
> It optionally takes a doc string.
> And then some lists follow, which should have the parameter vector as
> their first argument, and then the body.

Interesting.  It reminds me of the way the functional languages
like OCaml work:

# let rest = function
      []     ->  []
    | a :: b ->  b
 
From: André Thieme
Subject: Re: about pushnew
Date: 
Message-ID: <gnskmb$b4e$1@news.motzarella.org>
William James schrieb:
> Andr� Thieme wrote:
> 
>> For overloading the function to work on different arities you could
>> also do this:
>>
>> (defn pushnew
>>   "Documentation, available via (doc pushnew)"
>>   ([x coll] (pushnew x list =))
>>   ([x coll f] (if (not-any? #(f % x) coll)
>>                   (conj coll x)
>>                   coll)))
>>
>> So, defn takes the name, pushnew here.
>> It optionally takes a doc string.
>> And then some lists follow, which should have the parameter vector as
>> their first argument, and then the body.
> 
> Interesting.  It reminds me of the way the functional languages
> like OCaml work:
> 
> # let rest = function
>       []     ->  []
>     | a :: b ->  b
>  

You could get that too if you want.
You can write a macro, let�s call it defpattern.
Then you could say things like:
(defpattern is-empty
    | () -> true)

(defpattern fibonacci
      0 -> 1
    | 1 -> 1
    | n -> (+ (fibonacci (- n 1))
              (fibonacci (- n 2)))

Your macro would compile it into either a cond, or it will create
a (defmulti ...) and some (defmethod ...).


Andr�
-- 
Lisp is not dead. It�s just the URL that has changed:
http://clojure.org/
From: Harald Hanche-Olsen
Subject: Re: about pushnew
Date: 
Message-ID: <pcoskmv13yj.fsf@math.ntnu.no>
+ Pascal Costanza <··@p-cos.net>:

> ·······@eurogaran.com wrote:
>>> It can be argued that any function that has 2 arguments
>>> is a function of 2 arguments, inspite if it only uses one of them.
>> The function could even "decide" to use (or not) the second argument
>> based on the value of the first one, or the time of day...
>>
>> My opinion here is that the specification should not enforce :test to
>> be an operator with 2 arguments.
>
> You're confused.

So was I ...  I misunderstood what he was saying. Your analysis is
absolutely right, and my previous posts on this thread are off the
mark. Congratulations on your reading comprehension, which seems to
be better than mine today.

-- 
* Harald Hanche-Olsen     <URL:http://www.math.ntnu.no/~hanche/>
- It is undesirable to believe a proposition
  when there is no ground whatsoever for supposing it is true.
  -- Bertrand Russell
From: Kenneth Tilton
Subject: Re: about pushnew
Date: 
Message-ID: <4988fb56$0$25450$607ed4bc@cv.net>
Harald Hanche-Olsen wrote:
> + Pascal Costanza <··@p-cos.net>:
> 
>> ·······@eurogaran.com wrote:
>>>> It can be argued that any function that has 2 arguments
>>>> is a function of 2 arguments, inspite if it only uses one of them.
>>> The function could even "decide" to use (or not) the second argument
>>> based on the value of the first one, or the time of day...
>>>
>>> My opinion here is that the specification should not enforce :test to
>>> be an operator with 2 arguments.
>> You're confused.
> 
> So was I ...  I misunderstood what he was saying. Your analysis is
> absolutely right, and my previous posts on this thread are off the
> mark. Congratulations on your reading comprehension, which seems to
> be better than mine today.
> 

Don't encourage him, we need him to put down the books and get out and 
play more.

Meanwhile, when is one of you going to point out that the OP is looking 
for pushif?

<sigh>

kth
From: Harald Hanche-Olsen
Subject: Re: about pushnew
Date: 
Message-ID: <pcobpti8vly.fsf@math.ntnu.no>
+ Kenneth Tilton <·········@gmail.com>:

> Don't encourage him, we need him to put down the books and get out and
> play more.

8)

> Meanwhile, when is one of you going to point out that the OP is
> looking for pushif?

No need, you just pointed it out yourself.

-- 
* Harald Hanche-Olsen     <URL:http://www.math.ntnu.no/~hanche/>
- It is undesirable to believe a proposition
  when there is no ground whatsoever for supposing it is true.
  -- Bertrand Russell
From: Alex Mizrahi
Subject: Re: about pushnew
Date: 
Message-ID: <49896d34$0$90267$14726298@news.sunsite.dk>
 KT> Meanwhile, when is one of you going to point out that the OP is looking
 KT> for pushif?

I did! I did!
I called it push-unless, however. 
From: Kenneth Tilton
Subject: Re: about pushnew
Date: 
Message-ID: <4989a00f$0$24985$607ed4bc@cv.net>
Alex Mizrahi wrote:
>  KT> Meanwhile, when is one of you going to point out that the OP is looking
>  KT> for pushif?
> 
> I did! I did!
> I called it push-unless, however. 
> 
> 


Puh-leaze! A hyphen? Eschew peloria*! Should be pushunless. Meanwhile, 
do you know nothing of Lisp? Should be pushifnot!

hth,kth

* The abnormal appearance of regularity in a normally irregular 
phenomenon. hk
From: Harald Hanche-Olsen
Subject: Re: about pushnew
Date: 
Message-ID: <pcowsc71468.fsf@math.ntnu.no>
+ ·······@eurogaran.com:

>> It can be argued that any function that has 2 arguments
>> is a function of 2 arguments, inspite if it only uses one of them.
> The function could even "decide" to use (or not) the second argument
> based on the value of the first one, or the time of day...
>
> My opinion here is that the specification should not enforce :test to
> be an operator with 2 arguments.

It specifies the test function to have two arguments because that is the
only thing that makes any sense. It should not, and does not, require
the test function to actually use both arguments. See the difference?

-- 
* Harald Hanche-Olsen     <URL:http://www.math.ntnu.no/~hanche/>
- It is undesirable to believe a proposition
  when there is no ground whatsoever for supposing it is true.
  -- Bertrand Russell
From: Barry Margolin
Subject: Re: about pushnew
Date: 
Message-ID: <barmar-945A28.22303504022009@mara100-84.onlink.net>
In article 
<····································@x6g2000pre.googlegroups.com>,
 ·······@eurogaran.com wrote:

> My opinion here is that the specification should not enforce :test to
> be an operator with 2 arguments.

How can an equivalence function not require two arguments?

-- 
Barry Margolin, ······@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
*** PLEASE don't copy me on replies, I'll read them in the group ***
From: Kaz Kylheku
Subject: Re: about pushnew
Date: 
Message-ID: <20090211052502.264@gmail.com>
On 2009-02-05, Barry Margolin <······@alum.mit.edu> wrote:
> In article 
><····································@x6g2000pre.googlegroups.com>,
>  ·······@eurogaran.com wrote:
>
>> My opinion here is that the specification should not enforce :test to
>> be an operator with 2 arguments.
>
> How can an equivalence function not require two arguments?

Help! Kenny?
From: Thomas A. Russ
Subject: Re: about pushnew
Date: 
Message-ID: <ymibptjlzdq.fsf@blackcat.isi.edu>
·······@eurogaran.com writes:

> > i'm pretty sure that if it would work in your way it would not be
> > conformant, because NIL is not element of ().
> 
> Well, that remains debatable, since both (car ()) and (cdr ()) return
> nil

I don't think it's debatable at all.

First of all, () is different from (nil).

Second, (member nil ()) => nil
        (find nil ()) = nil
        (position nil ()) = nil

so there really is no support for NIL being an element of ().

CAR does not force membership.  In fact, the return value of NIL
is explicitly specified as the result.  CDR really has nothing to do
with membership, since it returns a subset of the original list.

-- 
Thomas A. Russ,  USC/Information Sciences Institute
From: Alex Mizrahi
Subject: Re: about pushnew
Date: 
Message-ID: <49896bc4$0$90264$14726298@news.sunsite.dk>
  k>>> The following code seems reasonable:
  k>>> (pushnew number list :test #'(lambda (a b) (= 3 a)))
 ??>>
 ??>> no, it does not. it looks like an idiotic hack.

 k> Indeed; except if substituting number we had
 k> (some_S-expression_that_returns_a_number)
 k> in which case it does not look so idiotic.

(let ((n (fn x)))  (unless (= n 3) (push n list)))

it is still shorter than your expression, it works correctly
and is much more readable.

if you're using it frequently, write a macro push-unless.

 ??>> test is meant to compare two items to check if they are same.
 k> Now you are touching on matter.
 k> It can be argued that any function that has 2 arguments
 k> is a function of 2 arguments, inspite if it only uses one of them.

yep, it is function of two arguments, technically it is correct,
but your function does not compare items as it should be pushnew semantics,
so you're violating semantics with it.

 k> I agree. My objective was only to pose an example as clear and simple
 k> as possible, not that it had any practical use.

that is a problem -- usually stuff that is not practical does not make 
sense.

 ??>> i'm pretty sure that if it would work in your way it would not be
 ??>> conformant, because NIL is not element of ().

 k> Well, that remains debatable, since both (car ()) and (cdr ()) return
 k> nil

even if they do, that won't make sense from math/logic point of view.
luckily, in Lisp (NIL) is different from ().

CL-USER> (position nil '())
NIL
CL-USER> (position nil '(NIL))
0
From: Harald Hanche-Olsen
Subject: Re: about pushnew
Date: 
Message-ID: <pco1vuf2jqo.fsf@math.ntnu.no>
+ ·······@eurogaran.com:

> Let's create an empty list, for instance with (setq list ())
> Now suppose I want to push a number into it only if said number is not
> 3.
> The following code seems reasonable:
> (pushnew number list :test #'(lambda (a b) (= 3 a)))

It is not reasonable, as has been pointed out by Alex Mizrahi. Supplying
pushnew with a test function that never uses its second argument makes
no sense, because it will call the test function once for every member
of the list where a single test should be sufficient.

> ...and in fact works... BUT ONLY WHEN list IS NOT EMPTY!
> In other words: the first element is always pushed onto list by
> pushnew, regardless of :test.
> This is the behavior in all the implementations I have tested.

Then you haven't tested it on SBCL, I think?

cl-user> (defparameter *foo* nil)
*foo*
cl-user> (defun foo (n)
	   (pushnew n *foo*
		    :test #'(lambda (a b)
			      (declare (ignore b))
			      (= 3 a))))
foo
cl-user> (foo 5)
(5)
cl-user> (foo 3)
(5)
cl-user> (foo 8)
(8 5)

> 1) Is it conformat?

Not as far as I can tell.

> 2) Is it desireable?

Non-conformance is never desirable.

> 3) Ideas on how to circumvent it?

See Marco Antoniotti's response. But if you really see the behaviour you
report, you should report it as an implementation bug.

-- 
* Harald Hanche-Olsen     <URL:http://www.math.ntnu.no/~hanche/>
- It is undesirable to believe a proposition
  when there is no ground whatsoever for supposing it is true.
  -- Bertrand Russell
From: Thomas A. Russ
Subject: Re: about pushnew
Date: 
Message-ID: <ymifxivlzlp.fsf@blackcat.isi.edu>
Harald Hanche-Olsen <······@math.ntnu.no> writes:

> > ...and in fact works... BUT ONLY WHEN list IS NOT EMPTY!
> > In other words: the first element is always pushed onto list by
> > pushnew, regardless of :test.
> > This is the behavior in all the implementations I have tested.
> 
> Then you haven't tested it on SBCL, I think?
> 
> cl-user> (defparameter *foo* nil)
> *foo*
> cl-user> (defun foo (n)
> 	   (pushnew n *foo*
> 		    :test #'(lambda (a b)
> 			      (declare (ignore b))
> 			      (= 3 a))))
> foo

But if you try (foo 3) here, before *foo* has any values, it will still
add 3 to the list and not execute the test function (for good reason,
since it would otherwise fail due to not having enough arguments).

[n.B. The following is not directed toward Harald in particular]

The moral of the story is that the degenerate cases are often defined in
ways that may not be intuitively obvious at first glance, so it is
necessary to either read the documentation closely or else apply some
common sense reasoning in cases like this.  (IIRC the spec doesn't
actually cover this particular detail, but it can be deduced that it
must work this way.)

The second moral, especially for the OP, is that it sometimes doesn't
pay to try to be TOO clever.  Of course, there are some neat
"techniques" that exploit clever uses of language features in
non-standard ways, but sometimes those attempts don't work on the edge
cases.  Like here.

-- 
Thomas A. Russ,  USC/Information Sciences Institute