Gmail Calendar Documents Reader Web more »
Recently Visited Groups | Help | Sign in
Google Groups Home
Fexprs more flexible, powerful, easier to learn? (Newlisp vs CL)
There are currently too many topics in this group that display first. To make this topic appear first, remove this option from another topic.
There was an error processing your request. Please try again.
flag
  Messages 1 - 25 of 93 - Collapse all  -  Translate all to Translated (View all originals)   Newer >
The group you are posting to is a Usenet group. Messages posted to this group will make your email address visible to anyone on the Internet.
Your reply message has not been sent.
Your post was successful
 
From:
To:
Cc:
Followup To:
Add Cc | Add Followup-to | Edit Subject
Subject:
Validation:
For verification purposes please type the characters you see in the picture below or the numbers you hear by clicking the accessibility icon. Listen and type the numbers you hear
 
Majorinc Kazimir  
View profile  
(2 users)  More options Jan 23, 3:32 pm
Newsgroups: comp.lang.lisp
From: Majorinc Kazimir <fa...@email.address>
Date: Fri, 23 Jan 2009 21:32:13 +0100
Local: Fri, Jan 23 2009 3:32 pm
Subject: Fexprs more flexible, powerful, easier to learn? (Newlisp vs CL)
;============================

Pascal:

But where is the paper that argues that fexprs are sometimes
better than macros because they are more flexible and
powerful than macros? Or easier to use, learn, etc? It sounds
like Mr.  Majorinc is confident enough that he should be
able to set about writing that paper. I'm looking forward to it!

;============================

I define macro (at-least-two arg1 ... argn)
that returns true if and only if at least
two of args evaluate to the true. Macro is
needed because we want lazy evaluation
of arg1 to argn, like in OR or AND.

Newlisp (17 tokens, very simple)

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

     ; test

     (println (at-least-two (= 1 1)
                            (= 3 2)
                            (= 2 5)
                            (= 2 20)))

     (exit)

(A) Could you write simpler, more elegant one in
     your favorite Lisp?

Only solution so far is Rainer Joswig's CL

     (defmacro at-least-two (&rest expressions)
       (let ((c (gensym)))
         `(let ((,c 0))
            (block nil
              ,@(loop for expression in expressions
                      collect `(when ,expression (incf ,c))
                      collect `(when (= ,c 2) (return t)))
              nil))))

It has 38 tokens, and I think it is significantly more
complicated (and not the first class.)

------------------------------------------------

(B) Fexprs are frequently described as "dangerous."
     Practice of Newlispers seems to be different:
     there are no complains. Probably because Newlispers
     typically use lexical / static scope constructs
     named "contexts."

     However, even without lexical scope, I believe
     that fexprs are pretty safe.

(B1) Is anyone able to find the expression that
      breaks at-least-two macro?

(B2) Is anyone able to find the expression that
      breaks at-least-two macro after trivial name
      mangling, for example, replacing i with
      at-least-two-i.

(B3) Is anyone able to find the expression that
      breaks at-least-two macro after single
      application of my function protect2 from
      my Newlisp library www.instprog.com,
      explained at my blog kazimirmajorinc.blogspot.com,
      post "Don't fear Dynamic Scope (2)"

------------------------------------------------
(C) I define more general macro at-least that should
accept expressions of the following kind:

(at-least 3 (= 1 1) (= 2 2) (= 4 4))
(at-least 7 (= 1 1) (= 7 2) ... )

Solution in Newlisp

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

Could you write simpler, more elegant one in
your favorite Lisp?


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Rainer Joswig  
View profile  
(1 user)  More options Jan 23, 5:02 pm
Newsgroups: comp.lang.lisp
From: Rainer Joswig <jos...@lisp.de>
Date: Fri, 23 Jan 2009 23:02:54 +0100
Local: Fri, Jan 23 2009 5:02 pm
Subject: Re: Fexprs more flexible, powerful, easier to learn? (Newlisp vs CL)
In article <gld9gr$m0...@ss408.t-com.hr>,
 Majorinc Kazimir <fa...@email.address> wrote:

Even if Newlisp names it a macro, it is not a macro.
It is a FEXPR. A Macro would do source transformation.
Above does not do any source transformation.

From Wikipedia, Macro

 A macro in computer science is a rule or pattern that
 specifies how a certain input sequence (often a
 sequence of characters) should be mapped to an
 output sequence (also often a sequence of characters)
 according to a defined procedure. The mapping process
 which instantiates a macro into a specific output
 sequence is known as macro expansion.

Your code does not map an input sequence to an
output sequence, thus it is no macro and the
form should be named DEFINE-FEXPR.

The 'first class'?

You are a token counter? Here are slightly less tokens
for your more general version.

(defmacro at-least (n &rest es &aux (c (gensym)))
  `(let ((,c 0))
      (or ,@(loop for e in es collect `(and ,e (= (incf ,c) ,n))))))

Again your FEXPR fails to show the generated code,
because it can't.

Common Lisp can show me the generated code:

CL-USER 91 > (pprint (macroexpand-1 '(at-least 2 (= 1 1) (= 3 2) (= 2 2) (= 4 4))))

(LET ((#:G14745 0))
  (OR (AND (= 1 1) (= (INCF #:G14745) 2))
      (AND (= 3 2) (= (INCF #:G14745) 2))
      (AND (= 2 2) (= (INCF #:G14745) 2))
      (AND (= 4 4) (= (INCF #:G14745) 2))))

Well, your version iterates over all forms, counts the true values
and then returns if the sum is equal or greater to 2. So, it does NOT
stop when 2 is already reached.

Let me change my version so that it does the same:

(defmacro at-least (n &rest es &aux (c (gensym)))
  `(let ((,c 0))
     ,@(loop for e in es collect `(when ,e (incf ,c)))
     (>= ,c ,n)))

CL-USER 98 > (pprint (macroexpand-1 '(at-least 2 (= 1 1) (= 3 2) (= 2 2) (= 4 4))))

(LET ((#:G14786 0))
  (WHEN (= 1 1) (INCF #:G14786))
  (WHEN (= 3 2) (INCF #:G14786))
  (WHEN (= 2 2) (INCF #:G14786))
  (WHEN (= 4 4) (INCF #:G14786))
  (>= #:G14786 2))

The Newlisp manual also seems to have a wrong example for lambda-macro:

http://www.newlisp.org/newlisp_manual.html

  (lambda-macro (a b) (set (eval a) b))  evaluates to (lambda (x) (* x x))

That would surprise me...

--
http://lispm.dyndns.org/


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Kaz Kylheku  
View profile  
(2 users)  More options Jan 23, 5:24 pm
Newsgroups: comp.lang.lisp
From: Kaz Kylheku <kkylh...@gmail.com>
Date: Fri, 23 Jan 2009 22:24:09 +0000 (UTC)
Local: Fri, Jan 23 2009 5:24 pm
Subject: Re: Fexprs more flexible, powerful, easier to learn? (Newlisp vs CL)
On 2009-01-23, Majorinc Kazimir <fa...@email.address> wrote:

> ;============================

> Pascal:

> But where is the paper that argues that fexprs are sometimes
> better than macros because they are more flexible and
> powerful than macros? Or easier to use, learn, etc? It sounds
> like Mr.  Majorinc is confident enough that he should be
> able to set about writing that paper. I'm looking forward to it!

Pascal didn't write that.

> Newlisp (17 tokens, very simple)

Well, we have to give him credit for counting tokens.
J. Harrop counts characters:

  [He can bore with Eff Sharp.
   He can snooze with Oh Camel.
   He measures code size
   at the character level.]

So, token count translates to flexiblity and power. Hmm!

>      (define-macro (at-least-two)
>               (let (c)

You didn't initialize c to zero, and you're incrementing it. You mean nil is
zero in newLISP? Or uninitialized variables are 0 instead of nil?

>                    (doargs (i (= c 2))

So trailing args are implicit, like "$@" in the Bourne shell.

>                            (if (eval i)
>                                (inc c)))
>                    (>= c 2)))

Why the double evaluation of the condition with respect to C?

(defun at-least-n (n-func &rest funcs)
  (loop with limit = (funcall n-func)
        with c = 0
        for f in funcs
        when (funcall f) do (incf c)
        when (>= c limit) do (return t)))

(defmacro lambda-call (function &rest exprs)
 `(funcall ,function ,@(mapcar (lambda (expr) `(lambda nil ,expr)) exprs)))

(lambda-call 'at-least-n 3 (print 'a) (print 'b) nil (print 'c) (print 'd))

  -> T

  output:
  A
  B
  C

Though LAMBDA-CALL is a special form, AT-LEAST-N is a first class function that
takes functional arguments:

  (at-least-n (lambda () 3) (lambda () (print 'a)) ...)

Lambdas are compiled when the program in which they are contained is compiled,
and give you access to lexical variables. E.g.:

  (let ((foo 42))
    (lambda-call #'funcall (incf foo))
    foo))

Your own ``first class'' while loop:

 (defun while (guard &rest body)
   (loop while (funcall guard)
         do (mapcar #'funcall body)))

  (let ((x 0))
    (lambda-call #'while (< x 10) (print x) (incf x)))

  -> NIL

  Output:
  0
  1
  2
  3
  4
  5
  6
  7
  8
  9

There is no need to have functions that take unevaluated arguments, because you
can make a special operator like LAMBDA-CALL that gives you syntactic sugar
into turning forms into the bodies of simple functions, and passing the
resulting functions to a function. The function then uses FUNCALL to
``evaluate'' these compiled bodies rather than EVAL. (Above, the function /is/
FUNCALL).

Though lambda-call isn't first class, it doesn't matter because it is one of a
kind. You would be indirecting upon different functions, not upon different
operators similar to LAMBDA-CALL.

> (B) Fexprs are frequently described as "dangerous."
>      Practice of Newlispers seems to be different:
>      there are no complains.

You could dunk a newlisper into a vat of shit up to just below the level of his
nostrils and he wouldn't dare move, or open his mouth to complain. :)

> (B1) Is anyone able to find the expression that
>       breaks at-least-two macro?

You did, apparently, see below:

> (B3) Is anyone able to find the expression that
>       breaks at-least-two macro after single
>       application of my function protect2 from

Otherwise why would you need protect2. Is there going to be a protect3
to protect protect2? ;)

    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Kaz Kylheku  
View profile  
(2 users)  More options Jan 23, 5:46 pm
Newsgroups: comp.lang.lisp
From: Kaz Kylheku <kkylh...@gmail.com>
Date: Fri, 23 Jan 2009 22:46:00 +0000 (UTC)
Subject: Re: Fexprs more flexible, powerful, easier to learn? (Newlisp vs CL)
On 2009-01-23, Rainer Joswig <jos...@lisp.de> wrote:

> In article <gld9gr$m0...@ss408.t-com.hr>,
>  Majorinc Kazimir <fa...@email.address> wrote:
>>      (define-macro (at-least-two)
>>               (let (c)
>>                    (doargs (i (= c 2))
>>                            (if (eval i)
>>                                (inc c)))
>>                    (>= c 2)))
> Well, your version iterates over all forms, counts the true values
> and then returns if the sum is equal or greater to 2. So, it does NOT
> stop when 2 is already reached.

I thought that for a second too, but it looks as if the DOARGS form used in the
newLISP ``macro'' definition takes the second form as an extra guard:

  (doargs (i (= i 2) ...)
  (>= i 2)

I.e. `(doargs (,var ,until-expr) ...).  So DOARGS has a double condition for
terminating: implicitly running out of args, or the expression becoming true.

The code is slightly confusing because he it repeats the test again. After
the execution of the loop, it's not clear whether it terminated because it ran
out of arguments, or because i reached the maximum value.

It's like those silly C programs that do:

  for (i = 0; i < N; i++) {
    /* ... */
    if (found)
      break;
  }

  if (i == N) {
     /* ooops not found */
  }

:)


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Dimiter malkia Stanev  
View profile  
 More options Jan 23, 5:59 pm
Newsgroups: comp.lang.lisp
From: "Dimiter \"malkia\" Stanev" <mal...@mac.com>
Date: Fri, 23 Jan 2009 14:59:57 -0800
Local: Fri, Jan 23 2009 5:59 pm
Subject: Re: Fexprs more flexible, powerful, easier to learn? (Newlisp vs CL)

> It's like those silly C programs that do:

>   for (i = 0; i < N; i++) {
>     /* ... */
>     if (found)
>       break;
>   }

>   if (i == N) {
>      /* ooops not found */
>   }

> :)

Duh... :) - It's.... just.... that today I wrote such code, for upcoming
patch for our game, hehe...

Off course I know that i would be N if nothing was found, right after
the loop, at least in most "C" compilers that would be the case
(compilers that I know, used, etc), but at least for one such compiler
and specific optimization options that wasn't the case - on it, i was
equal to N-1 after the cycle (or N+1, can't remmember) - I think it was
a SH3 CodeWarrior compiler that we used for early Dreamcast dev. But
memory might play tricks on me.

Actually I don't think the "C" standard covers that case, it's
implementation-specific (which means undefined, and UP-TO-YOU!), so
generally it's bad code, and I wrote such code just yesterday (yet I'm
relieved, as much of the codebase uses such style, so if it breaks,
it'll break many places).


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Kaz Kylheku  
View profile  
 More options Jan 23, 6:38 pm
Newsgroups: comp.lang.lisp
From: Kaz Kylheku <kkylh...@gmail.com>
Date: Fri, 23 Jan 2009 23:38:13 +0000 (UTC)
Local: Fri, Jan 23 2009 6:38 pm
Subject: Re: Fexprs more flexible, powerful, easier to learn? (Newlisp vs CL)
On 2009-01-23, Dimiter "malkia" Stanev <mal...@mac.com> wrote:

That's a ridiculous bug. I've had a few run-ins with Metrowerks warez.  One one
project I was helping some developers port some our code to a platform using
some CW IDE.  The stupid thing insisted on compiling everything with the same
compiler, either C or C++. Global switch! It wouldn't look at the .cc and .c
suffixes of the files. The target was in the mc68K (old PalmOS).  The compiler
wouldn't emit larger than 16 bit jumps between functions, so object files
couldn't compile to more than 64K of code. A couple of our large C++ modules
had to be split into separate .cc files. IIRC, I put my foot down about that;
and had it implemented as multiple translation units in one source file with
some #ifdefs and multiple compiler passes, to keep the file intact for the sake
of merges and such.

> Actually I don't think the "C" standard covers that case, it's

When you speak about a programming language standard without having seen
so much as its cover page, sorry, that's not thinking!

Given a loop like for (i = 0; i < N; i++), provided that the loop does not have
some early break, and does not mess with the value of i; and provided that the
value N is not out of the range of the type of i; after the execution of that
loop, i must have the value N!  The predicate i == N is one of the basic
post-conditions of the loop, whose body keeps executing and incrementing i
while i < N.

On the last iteration, i is N-1 and the body is executed, and then the
increment step, which brings i to N. The guard is then evaluated (i < N) and
found to be false because i is N; the loop then terminates without doing
anything more to i.

> implementation-specific (which means undefined, and UP-TO-YOU!), so

Undefined does not mean up to you, it means up to your compiler implementors,
or else up to pure luck. Definitely not you, the programmer.

    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Dimiter malkia Stanev  
View profile  
 More options Jan 23, 6:49 pm
Newsgroups: comp.lang.lisp
From: "Dimiter \"malkia\" Stanev" <mal...@mac.com>
Date: Fri, 23 Jan 2009 15:49:42 -0800
Local: Fri, Jan 23 2009 6:49 pm
Subject: Re: Fexprs more flexible, powerful, easier to learn? (Newlisp vs CL)

> When you speak about a programming language standard without having seen
> so much as its cover page, sorry, that's not thinking!

True! We did have some local copy of C++ standard, but even if I read
it, it won't help us much - either the compiler wasn't following
anything, or once you learn it - you'll be always having the feeling
being a prick about why the compiler is stupid enough not to fix it.
There are even C/C++ compilers that claim to be 100% ANSI C, but then
again they either are not available, too obscure, or do not generate
optimized code.

I've actually stopped liking "C", much more because of "C++" and the
pressure it puts on people trying to grok it fully. (In fact I love "C",
but at work, I'm more or less forced to use "C++" and a "C++" without
exceptions and RTTI in the runtime (though we could use the latter only
for tools).

> Given a loop like for (i = 0; i < N; i++), provided that the loop does not have
> some early break, and does not mess with the value of i; and provided that the
> value N is not out of the range of the type of i; after the execution of that
> loop, i must have the value N!  The predicate i == N is one of the basic
> post-conditions of the loop, whose body keeps executing and incrementing i
> while i < N.

If that's in the standard, then I guess I was blindly coding the correct
stuff. Is there any reference online, where I can verify that (I'm
simply curious).

> On the last iteration, i is N-1 and the body is executed, and then the
> increment step, which brings i to N. The guard is then evaluated (i < N) and
> found to be false because i is N; the loop then terminates without doing
> anything more to i.

>> implementation-specific (which means undefined, and UP-TO-YOU!), so

That was really a joke (UP-TO-YOU) - it simply meant - do whatever you
need to do, just make this code work for the platforms you are targeting
(in our cases - that's mostly game consoles and PC).

> Undefined does not mean up to you, it means up to your compiler implementors,
> or else up to pure luck. Definitely not you, the programmer.

Yup.

Btw, I've learned quite a lot from your latest posts!

Cheers!


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
joswig@corporate-world.li sp.de  
View profile  
(1 user)  More options Jan 23, 7:00 pm
Newsgroups: comp.lang.lisp
From: "jos...@corporate-world.lisp.de" <jos...@corporate-world.lisp.de>
Date: Fri, 23 Jan 2009 16:00:09 -0800 (PST)
Local: Fri, Jan 23 2009 7:00 pm
Subject: Re: Fexprs more flexible, powerful, easier to learn? (Newlisp vs CL)
On Jan 23, 11:46 pm, Kaz Kylheku <kkylh...@gmail.com> wrote:

Ah, I see. Also, let me guess: if a form e1 of (atleast-two e1 e2 ...)
sets c to 1 and evaluates
to true, then it terminates already? Also: if e1 sets c to some non-
number and evaluates to true
then (inc c) fails.


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
André Thieme  
View profile  
(1 user)  More options Jan 23, 7:02 pm
Newsgroups: comp.lang.lisp
From: André Thieme <address.good.until.2009.may...@justmail.de>
Date: Sat, 24 Jan 2009 01:02:05 +0100
Local: Fri, Jan 23 2009 7:02 pm
Subject: Re: Fexprs more flexible, powerful, easier to learn? (Newlisp vs CL)
Majorinc Kazimir schrieb:

It looks not very complicated, but I wonder what
“(let (c)” means.
Is this in CL like  “(let ((c 0))”?

Will your code eval the first two args in any case?
Even if only one is given? It seems to me that the (eval i)
will take place in the case when at-least-two was called with
exactly one argument.

Here I have a version in Clojure. It will return nil if less than
two args were given. In the other case it will evaluate the first
two arguments:

(defmacro at-least-two [& r]
   (let [c (take 2 r)]
     (when (= 2 (count c))
       `(do ~@c))))

This version is even better than yours in my opinion.
It also has 17 tokens. Your version needs 150% of the lines of code of
my version, and my version is also shorter in character count:
user> (count "(define-macro (at-least-two)
(let (c)
(doargs (i (= c 2))
(if (eval i)
(inc c)))
(>= c 2)))")
91

vs

user> (count "(defmacro at-least-two [& r]
(let [c (take 2 r)]
(when (= 2 (count c))
`(do ~@c))))")
83

As you see, I did not count the leading spaces. So, your version does
not fall too far behind.
So, your version has nearly 10% more chars.
But the best feature about my version is, in my opinion of course,
that it is dramatically much more readable.
There are no side effects. No counter c is increased.
There is no need for a loop. I find it very clear.
Take up to 2 args out of the given args. When 2 args were taken, then
compile it into code (that’s the “do”).
Perhaps you will agree with me. But I am open to hear that your opinion
is different, and that you find your version easier and more readable.

This is of course very objective.
Although I think lots of programmers would agree that it will
be easier to understand if the side effect of incrementing a not
explicitly initialized counter and the loop could be eliminated.
So I would just do the same as you:

(defmacro at-least-two [n & r]
   (let [c (take n r)]
     (when (= n (count c))
       `(do ~@c))))

Again, I find my version simpler. Not much.
But, even for this short code, far more elegant.

André
--
Lisp is not dead. It’s just the URL that has changed:
http://clojure.org/


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Majorinc Kazimir  
View profile  
(2 users)  More options Jan 23, 7:17 pm
Newsgroups: comp.lang.lisp
From: Majorinc Kazimir <fa...@email.address>
Date: Sat, 24 Jan 2009 01:17:13 +0100
Local: Fri, Jan 23 2009 7:17 pm
Subject: Re: Fexprs more flexible, powerful, easier to learn? (Newlisp vs CL)

 > Well, your version iterates over all forms, counts the true values
 > and then returns if the sum is equal or greater to 2. So, it does NOT
 > stop when 2 is already reached.

You somehow made mistake. It does stop. For debugging
purpose I added one print.
-------------------
CODE:

(define-macro (at-least n)
          (let (c)
               (doargs (i (= c n))
                       (print i) ;;;;;; This one
                       (if (eval i)
                           (inc c)))
               (>= c n)))

(at-least 3 (= 1 1) (= 2 2) (= 3 3) (= 4 4) (= 5 5))
(exit)

----
OUTPUT:

(= 1 1)(= 2 2)(= 3 3)true
-----------------
It works.

> Even if Newlisp names it a macro, it is not a macro.
> It is a FEXPR. A Macro would do source transformation.
> Above does not do any source transformation.

I agree. As it is terminology issue, I decided to stay
with version that is used in two languages.

> (defmacro at-least (n &rest es &aux (c (gensym)))
>   `(let ((,c 0))
>       (or ,@(loop for e in es collect `(and ,e (= (incf ,c) ,n))))))

> Again your FEXPR fails to show the generated code,
> because it can't.

True, Newlisp macros (Lisp fexpr's) do not
necessarily generate code. But they COULD generate
the code if you really want it that way:

; Newlisp macro written in the Common Lisp style
(define-macro (at-least n)
   (println (append '(let (c))
                    (list
                       (cons 'or
                         (map (lambda(x)
                                (expand '(and x (inc c) (= c n))
                                        'x))
                              (args)))))))

This is fexpr that does exactly the same thing as your macro.
It generates code and prints it - if you want that it evaluates it,
just replace println with eval. It has 27 tokens. It is not natural to
force generating whole code in fexprs, but it is possible.

It was my original one:

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

As I myself wrote it, do you believe me that it was
easier?

>   (lambda-macro (a b) (set (eval a) b))  evaluates to (lambda (x) (* x x))

Yes, it is mistake. I'll report it, thanks.
In essence, it evaluates to

(lambda-macro (a b) (set (eval a) b))


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
joswig@corporate-world.li sp.de  
View profile  
(1 user)  More options Jan 23, 7:24 pm
Newsgroups: comp.lang.lisp
From: "jos...@corporate-world.lisp.de" <jos...@corporate-world.lisp.de>
Date: Fri, 23 Jan 2009 16:24:54 -0800 (PST)
Local: Fri, Jan 23 2009 7:24 pm
Subject: Re: Fexprs more flexible, powerful, easier to learn? (Newlisp vs CL)
On Jan 24, 1:02 am, André Thieme <address.good.until.

The task, as I understand it, was not to check if there are two args
and evaluate those.
The task is to evaluate the all args until at least two have been
evaluated to true.

> This version is even better than yours in my opinion.
> It also has 17 tokens. Your version needs 150% of the lines of code of
> my version, and my version is also shorter in character count:

a character counter

...


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Kaz Kylheku  
View profile  
 More options Jan 23, 7:30 pm
Newsgroups: comp.lang.lisp
From: Kaz Kylheku <kkylh...@gmail.com>
Date: Sat, 24 Jan 2009 00:30:40 +0000 (UTC)
Local: Fri, Jan 23 2009 7:30 pm
Subject: Re: Fexprs more flexible, powerful, easier to learn? (Newlisp vs CL)
On 2009-01-24, André Thieme <address.good.until.2009.may...@justmail.de> wrote:

> (defmacro at-least-two [& r]
>    (let [c (take 2 r)]
>      (when (= 2 (count c))
>        `(do ~@c))))

That's not what his ``macro'' (frexp) does. It keeps evaluating
expressions left to right until it runs out, or until it has encountered
two that are true. It then stops evaluating, and returns true if two had been
found true, otherwise false.

So you cannot simply take two expressions and ignore the rest.

Your macro also can't just not emit any code at all when there are fewer than
two expressions. The expressions may have side effects. If there is only one
expression, you know that the result will have to be false, but the effect
of that expression still has to take place.

> This version is even better than yours in my opinion.

But it's not first class like a frexp. :)

> As you see, I did not count the leading spaces.

In general, a fairly good comparison for size of Lisp code is the number of
atoms in the tree structure of the forms (say, including ()/NIL). (a (b c) d)
has the same size as (a b c d). Same atom count, same cons count, different
tree balance. (There are obvious ways to extend this to other languages; give
them a very charitable, if informal, s-exp conversion and use that).

    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
joswig@corporate-world.li sp.de  
View profile  
(1 user)  More options Jan 23, 7:34 pm
Newsgroups: comp.lang.lisp
From: "jos...@corporate-world.lisp.de" <jos...@corporate-world.lisp.de>
Date: Fri, 23 Jan 2009 16:34:02 -0800 (PST)
Local: Fri, Jan 23 2009 7:34 pm
Subject: Re: Fexprs more flexible, powerful, easier to learn? (Newlisp vs CL)
On Jan 24, 1:17 am, Majorinc Kazimir <fa...@email.address> wrote:

>  > Well, your version iterates over all forms, counts the true values
>  > and then returns if the sum is equal or greater to 2. So, it does NOT
>  > stop when 2 is already reached.

> You somehow made mistake. It does stop. For debugging
> purpose I added one print.

I did not look to close at DOARGS, my fault.

> > Even if Newlisp names it a macro, it is not a macro.
> > It is a FEXPR. A Macro would do source transformation.
> > Above does not do any source transformation.

> I agree. As it is terminology issue, I decided to stay
> with version that is used in two languages.

Like Newlisp is mostly not a new Lisp.

No, doubt, you can not only morph code into data and evaluate the
data,
you can also morph code into data, generate more data out of that and
evaluate that data. Common Lisp shows that none of that
is necessary.

> It was my original one:

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

> As I myself wrote it, do you believe me that it was
> easier?

It is not that much how easy it is, it is about how horrible it will
be to debug any non-trivial amount of code using FEXPRs.

...


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Majorinc Kazimir  
View profile  
 More options Jan 23, 7:47 pm
Newsgroups: comp.lang.lisp
From: Majorinc Kazimir <fa...@email.address>
Date: Sat, 24 Jan 2009 01:47:34 +0100
Local: Fri, Jan 23 2009 7:47 pm
Subject: Re: Fexprs more flexible, powerful, easier to learn? (Newlisp vs CL)

> Ah, I see. Also, let me guess: if a form e1 of (atleast-two e1 e2 ...)
> sets c to 1 and evaluates
> to true, then it terminates already? Also: if e1 sets c to some non-
> number and evaluates to true
> then (inc c) fails.

Right. That was (B1).

>> I.e. `(doargs (,var ,until-expr) ...).  So DOARGS has a double condition for
>> terminating: implicitly running out of args, or the expression becoming true.

>> The code is slightly confusing because he it repeats the test again. After
>> the execution of the loop, it's not clear whether it terminated because it ran
>> out of arguments, or because i reached the maximum value.

Yes.

    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
joswig@corporate-world.li sp.de  
View profile  
(1 user)  More options Jan 23, 8:12 pm
Newsgroups: comp.lang.lisp
From: "jos...@corporate-world.lisp.de" <jos...@corporate-world.lisp.de>
Date: Fri, 23 Jan 2009 17:12:13 -0800 (PST)
Local: Fri, Jan 23 2009 8:12 pm
Subject: Re: Fexprs more flexible, powerful, easier to learn? (Newlisp vs CL)
On Jan 24, 1:47 am, Majorinc Kazimir <fa...@email.address> wrote:

> > Ah, I see. Also, let me guess: if a form e1 of (atleast-two e1 e2 ...)
> > sets c to 1 and evaluates
> > to true, then it terminates already? Also: if e1 sets c to some non-
> > number and evaluates to true
> > then (inc c) fails.

> Right. That was (B1).

My Common Lisp version does not have that problem. Maybe you want to
your increase token count a bit and show a safer version?

Let me guess:  (let ((i 'something)) (at-least-two (eval i)))   also
does not work.
doargs sets i to the list (eval i), and then evaluates it... which
does what?


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
André Thieme  
View profile  
(1 user)  More options Jan 23, 8:13 pm
Newsgroups: comp.lang.lisp
From: André Thieme <address.good.until.2009.may...@justmail.de>
Date: Sat, 24 Jan 2009 02:13:59 +0100
Local: Fri, Jan 23 2009 8:13 pm
Subject: Re: Fexprs more flexible, powerful, easier to learn? (Newlisp vs CL)
Thanks to Rainer and Kaz for explanations.
Maybe this one is right?
Anyway, the fact that I didn’t understood (and still don’t understand
it well) the NewLisp code means at least for me it was not easy enough
to read. Perhaps I am just not trained enough in NewLisp.
(and I also did not look at the CL example and I didn’t follow the
discussion before)

(defmacro at-least-two [& x]
   `(= 2 (count (take 2 (filter eval '~x)))))

filter will lazily feed eval with the args that were passed to the macro.
Besides that, filter is like CLs remove-if-not.

This macro will eval all args passed to at-least-two until a maximum of
two of these args evaled to true. (that is: not “nil” and not “false”).
As Kaz suggested, now even those args that eval to nil or false will be
run, so side effects take place.

Obviously I find this version even more elegant than the one before.
And it is even shorter.
@Rainer: of course, counting characters is a very idiotic thing. But
it still is enjoyable for me to do it, because I feel a little bit like
“beat ‘em with their own weapons”.
I am not seriously drawing conclusions from these 5 liners. I just do it
for the fun. Also Tamas complained in the past about it. I ask you two
to just let me continue, for special friends.
Mostly for guys like Jillian James :-)

André
--


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
joswig@corporate-world.li sp.de  
View profile  
 More options Jan 23, 8:22 pm
Newsgroups: comp.lang.lisp
From: "jos...@corporate-world.lisp.de" <jos...@corporate-world.lisp.de>
Date: Fri, 23 Jan 2009 17:22:05 -0800 (PST)
Local: Fri, Jan 23 2009 8:22 pm
Subject: Re: Fexprs more flexible, powerful, easier to learn? (Newlisp vs CL)
On Jan 24, 2:13 am, André Thieme <address.good.until.

2009.may...@justmail.de> wrote:
> Thanks to Rainer and Kaz for explanations.
> Maybe this one is right?
> Anyway, the fact that I didn’t understood (and still don’t understand
> it well) the NewLisp code means at least for me it was not easy enough
> to read. Perhaps I am just not trained enough in NewLisp.
> (and I also did not look at the CL example and I didn’t follow the
> discussion before)

> (defmacro at-least-two [& x]
>    `(= 2 (count (take 2 (filter eval '~x)))))

It takes the first two and counts those?

Shouldn't it count the expressions that evaluate to true over all
items?

Will that see variables?

In CL

(let ((a t) (b nil) (c t))
  (at-least-two a b c))

?


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
André Thieme  
View profile  
 More options Jan 23, 8:54 pm
Newsgroups: comp.lang.lisp
From: André Thieme <address.good.until.2009.may...@justmail.de>
Date: Sat, 24 Jan 2009 02:54:42 +0100
Local: Fri, Jan 23 2009 8:54 pm
Subject: Re: Fexprs more flexible, powerful, easier to learn? (Newlisp vs CL)
jos...@corporate-world.lisp.de schrieb:

> On Jan 24, 2:13 am, André Thieme <address.good.until.
> 2009.may...@justmail.de> wrote:
>> Thanks to Rainer and Kaz for explanations.
>> Maybe this one is right?
>> Anyway, the fact that I didn’t understood (and still don’t understand
>> it well) the NewLisp code means at least for me it was not easy enough
>> to read. Perhaps I am just not trained enough in NewLisp.
>> (and I also did not look at the CL example and I didn’t follow the
>> discussion before)

>> (defmacro at-least-two [& x]
>>    `(= 2 (count (take 2 (filter eval '~x)))))

> It takes the first two and counts those?

Filter keeps only those elements which evaled to a different value than
nil or false.
If n args are giving filter can max return a list of n elements, like
remove-if-not in CL. In such a case it is like (mapcar #'identity list).
So, filter will return a list whose length is between 0 and n.
Out of this list take tries to take as many elements as possible, but
max 2. So, take can result in a list of the lengths 0, 1 or 2.

> Shouldn't it count the expressions that evaluate to true over all
> items?

I don’t know. I am not sure what the original poster really wanted.
As I don’t fully understand his code I have to guess.

> Will that see variables?

Good objection.

> In CL

> (let ((a t) (b nil) (c t))
>   (at-least-two a b c))

> ?

No, my version can’t see them.

André
--


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
joswig@corporate-world.li sp.de  
View profile  
 More options Jan 23, 9:02 pm
Newsgroups: comp.lang.lisp
From: "jos...@corporate-world.lisp.de" <jos...@corporate-world.lisp.de>
Date: Fri, 23 Jan 2009 18:02:46 -0800 (PST)
Local: Fri, Jan 23 2009 9:02 pm
Subject: Re: Fexprs more flexible, powerful, easier to learn? (Newlisp vs CL)
On Jan 24, 2:54 am, André Thieme <address.good.until.

Okay, looks good.

...

> > Will that see variables?

> Good objection.

> > In CL

> > (let ((a t) (b nil) (c t))
> >   (at-least-two a b c))

> > ?

> No, my version can’t see them.

You may need to increase token and character count...

    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Majorinc Kazimir  
View profile  
(2 users)  More options Jan 23, 9:34 pm
Newsgroups: comp.lang.lisp
From: Majorinc Kazimir <fa...@email.address>
Date: Sat, 24 Jan 2009 03:34:48 +0100
Local: Fri, Jan 23 2009 9:34 pm
Subject: Re: Fexprs more flexible, powerful, easier to learn? (Newlisp vs CL)
Newlisp 13 tokens for extended version:

(define-macro (at-least cnt)
    (exists (lambda(x)(zero? (and (eval x) (dec cnt)))) $args))


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Kaz Kylheku  
View profile  
 More options Jan 23, 10:31 pm
Newsgroups: comp.lang.lisp
From: Kaz Kylheku <kkylh...@gmail.com>
Date: Sat, 24 Jan 2009 03:31:24 +0000 (UTC)
Local: Fri, Jan 23 2009 10:31 pm
Subject: Re: Fexprs more flexible, powerful, easier to learn? (Newlisp vs CL)
On 2009-01-24, jos...@corporate-world.lisp.de <jos...@corporate-world.lisp.de>
wrote:

Once TAKE 2 pulls out two, it is done.  Pardon me, it must be COUNT that
actually pulls out the items. (TAKE 2) does nothing, just produces a virtual
sequence. If you don't use that value, no evaluation happens. But COUNT must
walk the whole sequence until the end, so it kicks TAKE into action, which
produces two items and then is done. In so doing, it must take at least two
items from the virtual sequence produced by the FILTER. FILTER will only
produce as many items as TAKE 2 asks for, i.e. at most two, but in so doing it
may process and filter out many forms that evaluate false. Once it produces two
truths though, it won't evaluate any more.

EVAL meets lazy sequences: a jam between psychedelic acid rock and progressive
metal!

:)

Let's do it in CL:

   (defun lazy-list (ordinary-list)
     (lambda ()
       (if ordinary-list
         (pop ordinary-list)
         (values nil t))))

   (defun lazy-filter (function lazy-list)
     (lambda ()
       (loop
         (multiple-value-bind (next nomore)
                              (funcall lazy-list)
           (cond
             (nomore (return (values nil t)))
             ((funcall function next) (return next)))))))

Test:

  [4]> (defparameter f (lazy-filter #'evenp (lazy-list '(1 2 3 4 5))))
  F
  [5]> (funcall f)
  2
  [6]> (funcall f)
  4
  [7]> (funcall f)
  NIL ;
  T
  [8]> (funcall f)
  NIL ;
  T

  (defun lazy-take (num lazy-list)
    (lambda ()
      (if (plusp (prog1 num (decf num)))
        (funcall lazy-list)
        (values nil t))))

  (defun lazy-count (lazy-list)
    (let ((count 0))
      (loop
        (multiple-value-bind (next nomore)
          (funcall lazy-list)
          (if nomore
            (return count)
            (incf count))))))

Now, transliterate the Clojure macro:

  (defmacro at-least-two (&rest x)
    `(= 2 (lazy-count (lazy-take 2 (lazy-filter #'eval (lazy-list ',x))))))

  [9]> (macroexpand '(at-least-two a b c d e))
  (= 2 (LAZY-COUNT (LAZY-TAKE 2 (LAZY-FILTER #'EVAL (LAZY-LIST '(A B C D E)))))) ;
  T

  [10]>   (at-least-two (princ 'a) nil nil (print 'b) (print 'c))
  AB
  T
  [11]>   (at-least-two (princ 'a) nil nil (print 'c))
  AC
  T
  [12]>   (at-least-two (princ 'a) (print 'c))
  AC
  T
  [13]>   (at-least-two (princ 'a))
  A
  NIL

Woiks for me!

> Will that see variables?

and must be ... FIRST ... CLASS!

Good grief. :)


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Discussion subject changed to "Fexprs more flexible, powerful, easier to learn? (Newlisp vsCL)" by William James
William James  
View profile  
(3 users)  More options Jan 23, 11:19 pm
Newsgroups: comp.lang.lisp
From: "William James" <w_a_x_...@yahoo.com>
Date: 24 Jan 2009 04:19:01 GMT
Local: Fri, Jan 23 2009 11:19 pm
Subject: Re: Fexprs more flexible, powerful, easier to learn? (Newlisp vsCL)

Majorinc Kazimir wrote:
> Newlisp 13 tokens for extended version:

> (define-macro (at-least cnt)
>    (exists (lambda(x)(zero? (and (eval x) (dec cnt)))) $args))

Ruby:

def at_least n, list
  list.any?{|x| eval x and 0 == n -= 1}
end

at_least 3, %w(1==1 2==2 3==3 4==4 5==5)


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Discussion subject changed to "Fexprs more flexible, powerful, easier to learn? (Newlisp vs CL)" by joswig@corporate-world.li sp.de
joswig@corporate-world.li sp.de  
View profile  
 More options Jan 24, 3:15 am
Newsgroups: comp.lang.lisp
From: "jos...@corporate-world.lisp.de" <jos...@corporate-world.lisp.de>
Date: Sat, 24 Jan 2009 00:15:28 -0800 (PST)
Local: Sat, Jan 24 2009 3:15 am
Subject: Re: Fexprs more flexible, powerful, easier to learn? (Newlisp vs CL)
On Jan 24, 3:34 am, Majorinc Kazimir <fa...@email.address> wrote:

> Newlisp 13 tokens for extended version:

> (define-macro (at-least cnt)
>     (exists (lambda(x)(zero? (and (eval x) (dec cnt)))) $args))

Still with the name capture problems.

    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
André Thieme  
View profile  
 More options Jan 24, 9:11 am
Newsgroups: comp.lang.lisp
From: André Thieme <address.good.until.2009.may...@justmail.de>
Date: Sat, 24 Jan 2009 15:11:05 +0100
Local: Sat, Jan 24 2009 9:11 am
Subject: Re: Fexprs more flexible, powerful, easier to learn? (Newlisp vs CL)
jos...@corporate-world.lisp.de schrieb:

>>> In CL
>>> (let ((a t) (b nil) (c t))
>>>   (at-least-two a b c))
>>> ?
>> No, my version can’t see them.

> You may need to increase token and character count...

Yes, you are right.
I was really too tired, did not get much sleep this week.
Okay, so here we go:

(defmacro at-least-two [& x]
   `(= 2 (count (take 2 (filter eval [~@x])))))

The change is what follows the “eval”.
It was:       '~x
And now is:  [~@x]

Explanation:
x will be a list of all given args in the macro.
Inside a backquote expression x is just the symbol x.
To unquote it one uses “~” in Clojure, as “,” is just
whitespace (for readability really nice, IMO).
~x would place the list of all given args behind the eval.
In the case of (at-least-two a b c) this would be
(a b c)
But (filter eval (a b c)) does not make much sense typically,
because the function a is not defined.
So, a call like:
(let [a nil, b nil, c false, d true] (at-least-two a b c d))
would result in a NullPointerException.

In my original version I did not think about variable capture,
so a call like:
(at-least-two 5 6 7)
would result in (filter eval (5 6 7)) which also makes no sense,
as Clojure can’t call 5.

That’s why I quoted the ~x in my macro:  '~x
Now (at-least-two 5 6 7) results in a (filter eval '(5 6 7)).
This however can’t work if variables are in the game, because those
would be treated literally, as symbols.

If Clojure would put the rest args into a vector instead of a list,
then ~x would have been okay. But as this does not happen I say:
[~x] which would be ==> [(5 6 7)]
But [~@x]  ==>  [5 6 7]
Now it is not quoted anymore, and also variables are treated properly:

user> (let [a nil, b nil, c false, d true] (at-least-two a b (println 5) d))
5
false

Note that the false is the return value of the call to at-least-two.
The 5 directly above it is what was printed. Note that println just
prints and returns nil. So, unlike CLs print it won’t return 5.

(let [a nil, b nil, c false, d true] (at-least-two  b a d  c d))
==> true

André
--
Lisp is not dead. It’s just the URL that has changed:
http://clojure.org/


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
André Thieme  
View profile  
 More options Jan 24, 9:15 am
Newsgroups: comp.lang.lisp
From: André Thieme <address.good.until.2009.may...@justmail.de>
Date: Sat, 24 Jan 2009 15:15:29 +0100
Local: Sat, Jan 24 2009 9:15 am
Subject: Re: Fexprs more flexible, powerful, easier to learn? (Newlisp vs CL)
Kaz Kylheku schrieb:

> On 2009-01-24, jos...@corporate-world.lisp.de <jos...@corporate-world.lisp.de>
> wrote:
>> On Jan 24, 2:13 am, André Thieme <address.good.until.
>> 2009.may...@justmail.de> wrote:
>>> (defmacro at-least-two [& x]
>>>    `(= 2 (count (take 2 (filter eval '~x)))))
>> It takes the first two and counts those?

>> Shouldn't it count the expressions that evaluate to true over all
>> items?

> Once TAKE 2 pulls out two, it is done.  Pardon me, it must be COUNT that
> actually pulls out the items.

Yes, you are absolutely right. Did you know that because you already
worked in Clojure? Or was this the result of your analysis?

 > (TAKE 2) does nothing, just produces a virtual sequence.

Exactly.

 > If you don't use that value, no evaluation happens. But COUNT must

> walk the whole sequence until the end, so it kicks TAKE into action, which
> produces two items and then is done. In so doing, it must take at least two
> items from the virtual sequence produced by the FILTER. FILTER will only
> produce as many items as TAKE 2 asks for, i.e. at most two, but in so doing it
> may process and filter out many forms that evaluate false. Once it produces two
> truths though, it won't evaluate any more.

Perfect explanation.
And thanks for your translation into CL.

André
--


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Messages 1 - 25 of 93   Newer >
« Back to Discussions « Newer topic     Older topic »

Create a group - Google Groups - Google Home - Terms of Service - Privacy Policy
©2009 Google