From: david
Subject: counting nils in a list
Date: 
Message-ID: <a3adb7bb-979f-4527-b643-181ee183023b@z9g2000yqi.googlegroups.com>
hello lispers,

i was inspired by this code from graham's acl:

(defun compress (x)
  (if (consp x)
      (compr (car x) 1 (cdr x))
      x))

(defun compr (elt n lst)
  (if (null lst)
      (list (n-elts elt n))
      (let ((next (car lst)))
        (if (eql next elt)
            (compr elt (+ n 1) (cdr lst))
            (cons (n-elts elt n)
                  (compr next 1 (cdr lst)))))))

(defun n-elts (elt n)
  (if (> n 1)
      (list n elt)
      elt))

to write a little program to generate forsythe edward notations.
i changed it a bit to make it work for my program.

now i try to write my own compress function to just
handle my particular case. thinking this will be easy
since i believe i understand the code above. and
also that will be simpler than a general compress
function. i also want to learn to design the recursive
function with car, cdr, and cons. so given a list like
'(nil nil B nil nil nil |k| nil)
i want it to return (2B3k1)
my usual approach of typing at the repl until something
works has failed me. i need a better design methodology.
all thoughts, comments, flames appreciated.
thanks, david

From: Pascal J. Bourguignon
Subject: Re: counting nils in a list
Date: 
Message-ID: <8763ibud3x.fsf@galatea.local>
david <······@gmail.com> writes:
> i was inspired by this code from graham's acl:
> [...]
> to write a little program to generate forsythe edward notations.
> i changed it a bit to make it work for my program.
>
> now i try to write my own compress function to just
> handle my particular case. thinking this will be easy
> since i believe i understand the code above. and
> also that will be simpler than a general compress
> function. i also want to learn to design the recursive
> function with car, cdr, and cons. so given a list like
> '(nil nil B nil nil nil |k| nil)
> i want it to return (2B3k1)
> my usual approach of typing at the repl until something
> works has failed me. i need a better design methodology.
> all thoughts, comments, flames appreciated.
> thanks, david

You can start from the result you want: (2B3k1)
What is it?  How can you get it?

It is a list containing one symbol sym.
We can get it using the function LIST:  (LIST SYM)

DONE.

Yes, really!

I can see you don't believe me.  Check it:

   (setf *print-escape* nil)
   (let ((sym '|2B3k1|))
      (LIST sym))
   --> (2B3k1)



We just need now to compute value of the symbol sym: 2B3k1
What is it?  How can you get it?

It is a symbol whose name is the concatenation of elements
representing a row of the chess board.
We can get it using the function INTERN, APPLY and CONCATENATE:

    (INTERN (APPLY (FUNCTION CONCATENATE) 'STRING elements))

{note that in our case, the maximum number of elements is 8, and the
minimum number of arguments accepted is 50, so we can use APPLY.}

DONE.

Yes, really!

Well, we must combine the two results:

   (let ((sym (INTERN (APPLY (FUNCTION CONCATENATE) 'STRING elements))))
      (LIST sym))

or, since sym is used only once:

   (LIST (INTERN (APPLY (FUNCTION CONCATENATE) 'STRING elements)))

but this is trivial.

I can see you don't believe me.  Check it:

   (let ((elements '("2" "B" "3" "k" "1")))
      (LIST (INTERN (APPLY (FUNCTION CONCATENATE) 'STRING elements))))
   --> (2B3k1)



We just need now to compute the list elements: ("2" "B" "3" "k" "1").
What is it?  How can you get it?

It is a list containing one element for each range of empty cell or
each cell occupied by a piece.  For a range of empty cell, it is a
string containing the number of empty cells in the range, in decimal.
For an  occupied cell, it is the letter representing the piece.  We
can get it by having a list chunks of empty ranges and occupied cells
such as:  ((nil nil) ("B") (nil nil nil) ("k") (nil)) {for occupied
cells, the letter of each cell is in its own list} and using MAPCAR,
LAMBDA, IF, NULL, LENGTH, PRINC-TO-STRING, FIRST:

  (MAPCAR (LAMBDA (ELEMENT) 
             (IF (NULL (FIRST ELEMENT))
                (PRINC-TO-STRING (LENGTH  ELEMENT))
                (FIRST ELEMENT))) 
          chunks)

DONE.

Yes, really!

Well, we must combine the two results:

   (LIST (INTERN  (APPLY (FUNCTION CONCATENATE) 'STRING 
                    (MAPCAR (LAMBDA (ELEMENT) 
                               (IF (NULL (FIRST ELEMENT))
                                  (PRINC-TO-STRING (LENGTH  ELEMENT))
                                  (FIRST ELEMENT))) 
                            chunks))))

I can see you don't believe me.  Check it:

    (let ((chunks '((nil nil) ("B") (nil nil nil) ("k") (nil))))
       (LIST (INTERN (APPLY (FUNCTION CONCATENATE) 'STRING 
                            (MAPCAR (LAMBDA (ELEMENT) 
                                        (IF (NULL (FIRST ELEMENT))
                                          (PRINC-TO-STRING (LENGTH  ELEMENT))
                                          (FIRST ELEMENT))) 
                                    chunks)))))
    --> (2B3k1)





We just need now to compute the list chunks: ((nil nil) ("B") (nil nil nil) ("k") (nil)).
What is it?  How can you get it?

It is a list of chunks. We can get it using REVERSE on the list
rchunks: ((NIL) ("k") (NIL NIL NIL) ("B") (NIL NIL))

DONE.

Yes, really!

Well, we must combine the two results:

   (LIST (INTERN  (APPLY (FUNCTION CONCATENATE) 'STRING 
                    (MAPCAR (LAMBDA (ELEMENT) 
                               (IF (NULL (FIRST ELEMENT))
                                  (PRINC-TO-STRING (LENGTH  ELEMENT))
                                  (FIRST ELEMENT))) 
                            (REVERSE rchunks)))))


I can see you don't believe me.  Check it:

    (let ((rchunks '((NIL) ("k") (NIL NIL NIL) ("B") (NIL NIL))))
       (LIST (INTERN (APPLY (FUNCTION CONCATENATE) 'STRING 
                            (MAPCAR (LAMBDA (ELEMENT) 
                                        (IF (NULL (FIRST ELEMENT))
                                          (PRINC-TO-STRING (LENGTH  ELEMENT))
                                          (FIRST ELEMENT))) 
                                    (REVERSE rchunks))))))
    --> (2B3k1)


Ok, this step may look a little strange.  Why would we want to start
from a reversed list of chunks?  Actually, this is because we tried
the following step, and saw that it's easier when processing a list of
cells to build the result rchunk in the reversed order.  In Lisp, this
is a usual idiom to process lists, unless you use a function such as
MAPCAR (or LOOP COLLECT).




We just need now to compute the list chunks: ((NIL) ("k") (NIL NIL NIL) ("B") (NIL NIL)).
What is it?  How can you get it?


It is a list containing lists of cells, computed from a list cells
such as (nil nil "B" nil nil nil "k" nil).  Contiguous empty cells are
gathered in one list, occupied cells are each in their own list.   We
could build it by processing each cell in cells, and depending on
whether it is empty of full, to prepend it to an empty range or as an
occupied cell.  

   (LET ((RCHUNKS '()))
      (DOLIST (CELL cells RCHUNKS)
         (IF (NULL CELL)
            (COND
              ((NULL RCHUNKS)        (PUSH (LIST CELL) RCHUNKS))
              ((NULL (CAAR RCHUNKS)) (PUSH CELL (CAR RCHUNKS)))
              (T                     (PUSH (LIST CELL) RCHUNKS)))
            (PUSH (LIST CELL) RCHUNKS))))
     
DONE.

Yes, really!

Well, we must combine the two results:

(LIST (INTERN
       (APPLY
        (FUNCTION CONCATENATE) 'STRING 
        (MAPCAR
         (LAMBDA (ELEMENT) 
             (IF (NULL (FIRST ELEMENT))
               (PRINC-TO-STRING (LENGTH  ELEMENT))
               (FIRST ELEMENT))) 
         (REVERSE (LET ((RCHUNKS '()))
                    (DOLIST (CELL cells RCHUNKS)
                      (IF (NULL CELL)
                        (COND
                          ((NULL RCHUNKS)        (PUSH (LIST CELL) RCHUNKS))
                          ((NULL (CAAR RCHUNKS)) (PUSH CELL (CAR RCHUNKS)))
                          (T                     (PUSH (LIST CELL) RCHUNKS)))
                        (PUSH (LIST CELL) RCHUNKS)))))))))

I can see you don't believe me.  Check it:

    (let ((cells '(nil nil "B" nil nil nil "k" nil)))
      (LIST (INTERN
             (APPLY
              (FUNCTION CONCATENATE) 'STRING 
              (MAPCAR
               (LAMBDA (ELEMENT) 
                   (IF (NULL (FIRST ELEMENT))
                     (PRINC-TO-STRING (LENGTH  ELEMENT))
                     (FIRST ELEMENT))) 
               (REVERSE (LET ((RCHUNKS '()))
                          (DOLIST (CELL cells RCHUNKS)
                            (IF (NULL CELL)
                              (COND
                                ((NULL RCHUNKS)        (PUSH (LIST CELL) RCHUNKS))
                                ((NULL (CAAR RCHUNKS)) (PUSH CELL (CAR RCHUNKS)))
                                (T                     (PUSH (LIST CELL) RCHUNKS)))
                              (PUSH (LIST CELL) RCHUNKS))))))))))
    --> (2B3k1)

We just need now to compute the list cells: (nil nil "B" nil nil nil "k" nil).
What is it?  How can you get it?

It is the input of your function.  We just have it.

Does it mean we're done?  YES!

Well, we must wrap it all in a DEFUN, and find a meaningful name for
this function:

  (DEFUN ENCODE-ROW-INTO-FEN (cells)
     "
Returns a list containing a symbol whose name is the concatenation of elements
representing a row of the chess board in the Forsythe Edward Notation.
"
     (LIST (INTERN
             (APPLY
              (FUNCTION CONCATENATE) 'STRING 
              (MAPCAR
               (LAMBDA (ELEMENT) 
                   (IF (NULL (FIRST ELEMENT))
                     (PRINC-TO-STRING (LENGTH  ELEMENT))
                     (FIRST ELEMENT))) 
               (REVERSE (LET ((RCHUNKS '()))
                          (DOLIST (CELL cells RCHUNKS)
                            (IF (NULL CELL)
                              (COND
                                ;; the first time, rchunks is ()
                                ((NULL RCHUNKS)        (PUSH (LIST CELL) RCHUNKS))
                                ;; rchunks is ((nil ...) ...)
                                ((NULL (CAAR RCHUNKS)) (PUSH CELL (CAR RCHUNKS)))
                                ;; rchunks is ("X" ...)
                                (T                     (PUSH (LIST CELL) RCHUNKS)))
                              (PUSH (LIST CELL) RCHUNKS))))))))))

(defun test/ENCODE-ROW-INTO-FEN ()
  (assert (equalp (mapcar (function ENCODE-ROW-INTO-FEN) 
                     '((nil nil "B" nil nil nil "k" nil)
                       ("R""N""B""K""Q""B""N""R")
                       (nil nil nil nil nil nil nil nil)
                       ("R""N"nil"K"nil nil "N""R")))
                  '((|2B3k1|) (|RNBKQBNR|) (|8|) (|RN1K2NR|))))
  :success)


(TEST/ENCODE-ROW-INTO-FEN)
--> :SUCCESS


In conclusion: it's really quite simple, you only have say what result
you need, to define and describe it precisely, then to determine how
you can get it from some intermediary results and simple operation,
and to repeat until the intermediary results are actually the input
parameters.  During all the process, you can check the chunks of code
you have so far work, applying them on a few example of intermediary
results.

It is also possible to start from the input parameters, and step by
step try to produce the end results, but it is often easier to do the
reverse.


-- 
__Pascal Bourguignon__
From: david
Subject: Re: counting nils in a list
Date: 
Message-ID: <1b97c38d-fb92-4e36-99e7-ac2992ad0dc0@h5g2000yqh.googlegroups.com>
On Mar 14, 2:18 pm, ····@informatimago.com (Pascal J. Bourguignon)
wrote:
a bunch of really cool stuff that will take some time to study

thanks 1e6, david
From: William James
Subject: Re: counting nils in a list
Date: 
Message-ID: <gph2i0024oc@enews2.newsguy.com>
Pascal J. Bourguignon wrote:

> 
>    (let ((elements '("2" "B" "3" "k" "1")))
>       (LIST (INTERN (APPLY (FUNCTION CONCATENATE) 'STRING elements))))
>    --> (2B3k1)

Clojure:

user=> (let [elements '("2" "B" "3" "k" "1")]
  (list (symbol (apply str elements))))
--> (2B3k1)


Ruby:

elements = %w(2 B 3 k 1)
[ elements.join.to_sym ]
    ==>[:"2B3k1"]
From: david
Subject: Re: counting nils in a list
Date: 
Message-ID: <f04ce31a-6a6a-40bd-ab84-1852bd01657e@e18g2000yqo.googlegroups.com>
On Mar 14, 3:03 pm, "William James" <·········@yahoo.com> wrote:
> Clojure:
>
> user=> (let [elements '("2" "B" "3" "k" "1")]
>   (list (symbol (apply str elements))))
> --> (2B3k1)
>
> Ruby:
>
> elements = %w(2 B 3 k 1)
> [ elements.join.to_sym ]
>     ==>[:"2B3k1"]

floopio:
f->!
From: Curt  Micol
Subject: Re: counting nils in a list
Date: 
Message-ID: <71bbea30-89c8-44f3-8715-a64871dd8ebe@q9g2000yqc.googlegroups.com>
On Mar 14, 3:18 pm, ····@informatimago.com (Pascal J. Bourguignon)
wrote:

This was an excellent tutorial, thank you for the break down.

I simply wish it wasn't distracted from by the crap these other people
feel they need to share.  Especially the Ruby guy who has taken what
can be a very beautiful language syntactically and just absolutely
murder it.

I know most hate Ruby here, but _it can be_ sexy sometimes, I am just
sorry that Mr. James doesn't understand that and instead presents
absolutely retarded code that doesn't even solve the problem
initially.
From: TomSW
Subject: Re: counting nils in a list
Date: 
Message-ID: <534e442a-0db9-4e7b-93b3-6556c30ea2b1@h5g2000yqh.googlegroups.com>
On Mar 15, 2:33 pm, Curt  Micol <·······@gmail.com> wrote:
> On Mar 14, 3:18 pm, ····@informatimago.com (Pascal J. Bourguignon)
> wrote:

> I know most hate Ruby here, but _it can be_ sexy sometimes, I am just
> sorry that Mr. James doesn't understand that and instead presents
> absolutely retarded code that doesn't even solve the problem
> initially.

MJ needs to participate in a software project with other people: the
most he posts the more other people are going to run a mile, which is
a shame for him & just plain tiresome for the rest of us.

ps I like Ruby :)

TomSW
From: ····················@hotmail.com
Subject: Re: counting nils in a list
Date: 
Message-ID: <a4d78091-d53b-4047-a479-dc71ef29184b@h20g2000yqn.googlegroups.com>
On 14 Mar, 19:18, ····@informatimago.com (Pascal J. Bourguignon)
wrote:
> david <······@gmail.com> writes:

> > i was inspired by this code from graham's acl:
> > [...]
> > to write a little program to generate forsythe edward notations.
> > i changed it a bit to make it work for my program.
>
> > now i try to write my own compress function to just
> > handle my particular case. thinking this will be easy
> > since i believe i understand the code above. and
> > also that will be simpler than a general compress
> > function. i also want to learn to design the recursive
> > function with car, cdr, and cons. so given a list like
> > '(nil nil B nil nil nil |k| nil)
> > i want it to return (2B3k1)
> > my usual approach of typing at the repl until something
> > works has failed me. i need a better design methodology.
> > all thoughts, comments, flames appreciated.
> > thanks, david
>
> You can start from the result you want: <some result>
> What is it?  How can you get it?
>
> It is <some description>
> We can get it using the function <some funcs>
>
> DONE.
>
> Yes, really!
>
> I can see you don't believe me.  Check it:
>
> <some test>
>
> We just need now to compute value of the symbol <some result>
> What is it?  How can you get it?

<snip>

So all we have to do now is code up Pascal's algorithm as a macro
and we'll never have to work again...

>
> In conclusion: it's really quite simple, you only have say what result
> you need, to define and describe it precisely, then to determine how
> you can get it from some intermediary results and simple operation,
> and to repeat until the intermediary results are actually the input
> parameters.  During all the process, you can check the chunks of code
> you have so far work, applying them on a few example of intermediary
> results.
>
> It is also possible to start from the input parameters, and step by
> step try to produce the end results, but it is often easier to do the
> reverse.

way cool!
From: Pascal J. Bourguignon
Subject: Re: counting nils in a list
Date: 
Message-ID: <7cab7la15o.fsf@pbourguignon.anevia.com>
····················@hotmail.com writes:

> On 14 Mar, 19:18, ····@informatimago.com (Pascal J. Bourguignon)
> wrote:
>>
>> You can start from the result you want: <some result>
>> What is it? �How can you get it?
>>
>> It is <some description>
>> We can get it using the function <some funcs>
>>
>> DONE.
>>
>> Yes, really!
>>
>> I can see you don't believe me. �Check it:
>>
>> <some test>
>>
>> We just need now to compute value of the symbol <some result>
>> What is it? �How can you get it?
>
> <snip>
>
> So all we have to do now is code up Pascal's algorithm as a macro
> and we'll never have to work again...

It's called the GPS, explained in PAIP.  ;-)

-- 
__Pascal Bourguignon__
From: Pascal J. Bourguignon
Subject: Re: counting nils in a list
Date: 
Message-ID: <87vdqbsx1y.fsf@galatea.local>
david <······@gmail.com> writes:

> hello lispers,
>
> i was inspired by this code from graham's acl:
> [...]
> to write a little program to generate forsythe edward notations.
> i changed it a bit to make it work for my program.
>
> now i try to write my own compress function to just
> handle my particular case. thinking this will be easy
> since i believe i understand the code above. and
> also that will be simpler than a general compress
> function. i also want to learn to design the recursive
> function with car, cdr, and cons. so given a list like
> '(nil nil B nil nil nil |k| nil)
> i want it to return (2B3k1)
> my usual approach of typing at the repl until something
> works has failed me. i need a better design methodology.
> all thoughts, comments, flames appreciated.

In the previous post we divided the problem into simplier subproblems
starting from the end.  It's kind of spamming.  Instead we could
divide it in coarse chunks, and finer and finer using higher level
functions.

For example, if we have a function such as cut-list-if, which can cut
a list between elements according to a predicate taking two successive
elements in the list, such as:

(cut-list-if (lambda (a b) (or a b))
            '(nil nil nil a nil nil nil a b nil nil nil
              a b c nil nil nil a b c d e nil))
--> ((NIL NIL NIL) (A) (NIL NIL NIL) (A) (B) (NIL NIL NIL) (A) (B) (C)
     (NIL NIL NIL) (A) (B) (C) (D) (E) (NIL))


we could write:


  (defun ENCODE-ROW-INTO-FEN (cells)
    (list (intern
           (format nil "~{~A~}"
                   (mapcar (lambda (range)
                               (if (stringp (first range))
                                 (first range)
                                 (length range)))
                           (cut-list-if (lambda (a b) (or a b)) cells))))))

C/USER[222]> (TEST/ENCODE-ROW-INTO-FEN)
:SUCCESS



Once you have an idea of some algorithm to solve your problem you can
simplify it.  For example, it is useless to build lists of nils just
to compute their length later. We can directly compute the length.

  (defun ENCODE-ROW-INTO-FEN (cells)
    (loop
       :with results = '()
       :for cell :in cells
       :do (cond
             (cell                       (push cell results))
             ((integerp (first results)) (incf (first results)))
             (t                          (push 1 results)))
       :finally (return (list (intern (format nil "~{~A~}" (reverse results)))))))


C/USER[237]> (TEST/ENCODE-ROW-INTO-FEN)
:SUCCESS

-- 
__Pascal Bourguignon__
From: William James
Subject: Re: counting nils in a list
Date: 
Message-ID: <gph44q02698@enews2.newsguy.com>
Pascal J. Bourguignon wrote:

> 
>   (defun ENCODE-ROW-INTO-FEN (cells)
>     (loop
>        :with results = '()
>        :for cell :in cells
>        :do (cond
>              (cell                       (push cell results))
>              ((integerp (first results)) (incf (first results)))
>              (t                          (push 1 results)))
>        :finally (return (list (intern (format nil "~{~A~}" (reverse results)))))))

Are you completely dependent on and helpless without "loop"?
Haven't you ever heard of reduce or fold?  Do you pride yourself
on the bloated, prolix COBOL-ness of your Commune Lisp code?

Ruby:

[nil,"K",nil,nil,nil,nil,nil,"R"].inject([]){|a,x|
  if x then a << x else a[-1] += 1 rescue a << 1 end
  a }.join
    ==>"1K5R"
From: John Thingstad
Subject: Re: counting nils in a list
Date: 
Message-ID: <op.uqs6ozcfut4oq5@pandora.alfanett.no>
P� Sat, 14 Mar 2009 21:30:18 +0100, skrev William James  
<·········@yahoo.com>:

> Pascal J. Bourguignon wrote:
>
>>
>>   (defun ENCODE-ROW-INTO-FEN (cells)
>>     (loop
>>        :with results = '()
>>        :for cell :in cells
>>        :do (cond
>>              (cell                       (push cell results))
>>              ((integerp (first results)) (incf (first results)))
>>              (t                          (push 1 results)))
>>        :finally (return (list (intern (format nil "~{~A~}" (reverse  
>> results)))))))
>
> Are you completely dependent on and helpless without "loop"?
> Haven't you ever heard of reduce or fold?  Do you pride yourself
> on the bloated, prolix COBOL-ness of your Commune Lisp code?
>
> Ruby:
>
> [nil,"K",nil,nil,nil,nil,nil,"R"].inject([]){|a,x|
>   if x then a << x else a[-1] += 1 rescue a << 1 end
>   a }.join
>     ==>"1K5R"

Yes we like loop. It save us the processing time of decyphering the Ruby  
line noice.

--------------
John Thingstad
From: =?UTF-8?B?QW5kcsOpIFRoaWVtZQ==?=
Subject: Re: counting nils in a list
Date: 
Message-ID: <gphs19$uor$1@news.motzarella.org>
William James schrieb:
> Pascal J. Bourguignon wrote:
> 
>>   (defun ENCODE-ROW-INTO-FEN (cells)
>>     (loop
>>        :with results = '()
>>        :for cell :in cells
>>        :do (cond
>>              (cell                       (push cell results))
>>              ((integerp (first results)) (incf (first results)))
>>              (t                          (push 1 results)))
>>        :finally (return (list (intern (format nil "~{~A~}" (reverse results)))))))
> 
> Are you completely dependent on and helpless without "loop"?
> Haven't you ever heard of reduce or fold?  Do you pride yourself
> on the bloated, prolix COBOL-ness of your Commune Lisp code?
> 
> Ruby:
> 
> [nil,"K",nil,nil,nil,nil,nil,"R"].inject([]){|a,x|
>   if x then a << x else a[-1] += 1 rescue a << 1 end
>   a }.join
>     ==>"1K5R"

Lisp:
(use 'clojure.contrib.seq-utils)

(defn hallo [coll]
   (apply str (map (fn [[x :as all]] (or x (count all)))
                   (partition-by nil? coll))))

When you add „def hallo coll” and „end”, then the Lisp function and the
Ruby function both are 100 chars long, when written in one line.

(hallo [nil,"K",nil,nil,nil,nil,nil,nil nil nil nil nil nil nil "R"])
==> "1K12R"

Instead of the strings one could as well use symbols, such as 'K
or characters, for example \R


André
-- 
Lisp is not dead. It’s just the URL that has changed:
http://clojure.org/
From: Pascal J. Bourguignon
Subject: Re: counting nils in a list
Date: 
Message-ID: <87mybnswun.fsf@galatea.local>
···@informatimago.com (Pascal J. Bourguignon) writes:
> For example, if we have a function such as cut-list-if, which can cut
> a list between elements according to a predicate taking two successive
> elements in the list, such as:
>
> (cut-list-if (lambda (a b) (or a b))
>             '(nil nil nil a nil nil nil a b nil nil nil
>               a b c nil nil nil a b c d e nil))
> --> ((NIL NIL NIL) (A) (NIL NIL NIL) (A) (B) (NIL NIL NIL) (A) (B) (C)
>      (NIL NIL NIL) (A) (B) (C) (D) (E) (NIL))

Oops, I forgot to present a CUT-LIST-IF:

(defun cut-list-if (predicate list)
  (loop
     :with results = '()
     :with sublist = '()
     :for (a b) :on list
     :do (if (funcall predicate a b)
           (progn
             (push a sublist)
             (push sublist results)
             (setf sublist '()))
           (push a sublist))
     :finally (when sublist (push sublist results)) (return (reverse results))))


-- 
__Pascal Bourguignon__
From: William James
Subject: Re: counting nils in a list
Date: 
Message-ID: <gph6ks027t7@enews2.newsguy.com>
Pascal J. Bourguignon wrote:

> 
> (defun cut-list-if (predicate list)
>   (loop
>      :with results = '()
>      :with sublist = '()
>      :for (a b) :on list
>      :do (if (funcall predicate a b)
>            (progn
>              (push a sublist)
>              (push sublist results)
>              (setf sublist '()))
>            (push a sublist))
>      :finally (when sublist (push sublist results)) (return (reverse results))))

Ruby:


def cut_if list
  result = []
  sublist = []
  list.each_index{|i|
    a,b = list[i,2]
    if yield( a, b )
      result << (sublist << a)
      sublist = []
    else   sublist << a    end }
  if sublist.empty? then  result else result << sublist end
end

p cut_if( [nil,nil,:a,nil,nil,:a,:b,nil,:a,:b,:c,nil] ){|a,b| a or b}
p cut_if( [nil,nil,:a,nil,nil,:a,:b,nil,:a,:b,:c] ){|a,b| a or b}

--- output ---
[[nil, nil], [:a], [nil, nil], [:a], [:b], [nil], [:a], [:b], [:c], [nil]]
[[nil, nil], [:a], [nil, nil], [:a], [:b], [nil], [:a], [:b], [:c]]
From: =?UTF-8?B?QW5kcsOpIFRoaWVtZQ==?=
Subject: Re: counting nils in a list
Date: 
Message-ID: <gphamh$c34$1@news.motzarella.org>
William James schrieb:

> Ruby:
> 
> 
> def cut_if list
>   result = []
>   sublist = []
>   list.each_index{|i|
>     a,b = list[i,2]
>     if yield( a, b )
>       result << (sublist << a)
>       sublist = []
>     else   sublist << a    end }
>   if sublist.empty? then  result else result << sublist end
> end
> 
> p cut_if( [nil,nil,:a,nil,nil,:a,:b,nil,:a,:b,:c,nil] ){|a,b| a or b}
> p cut_if( [nil,nil,:a,nil,nil,:a,:b,nil,:a,:b,:c] ){|a,b| a or b}
> 
> --- output ---
> [[nil, nil], [:a], [nil, nil], [:a], [:b], [nil], [:a], [:b], [:c], [nil]]
> [[nil, nil], [:a], [nil, nil], [:a], [:b], [nil], [:a], [:b], [:c]]

Lisp:
(use 'clojure.contrib.seq-utils)
(defn cut-if [coll] (partition-by identity coll))


André
-- 
Lisp is not dead. It’s just the URL that has changed:
http://clojure.org/
From: TomSW
Subject: Re: counting nils in a list
Date: 
Message-ID: <b9c3f28c-1d12-4679-bdc8-71937b5a0680@13g2000yql.googlegroups.com>
On Mar 14, 11:22 pm, André Thieme <address.good.until.
···········@justmail.de> wrote:

> (use 'clojure.contrib.seq-utils)
> (defn cut-if [coll] (partition-by identity coll))

(partition-by identity '(a a b c nil nil nil d e f))
-> ((a a) (b) (c) (nil nil nil) (d) (e) (f))

out of interest, how could one use partition-by here to get:
((a) (a) (b) (c) (nil nil nil) ...) instead, ie, only clump nils?

TomSW
From: André Thieme
Subject: Re: counting nils in a list
Date: 
Message-ID: <gphpnf$ea1$1@news.motzarella.org>
TomSW schrieb:
> On Mar 14, 11:22 pm, Andr� Thieme <address.good.until.
> ···········@justmail.de> wrote:
> 
>> (use 'clojure.contrib.seq-utils)
>> (defn cut-if [coll] (partition-by identity coll))
> 
> (partition-by identity '(a a b c nil nil nil d e f))
> -> ((a a) (b) (c) (nil nil nil) (d) (e) (f))
> 
> out of interest, how could one use partition-by here to get:
> ((a) (a) (b) (c) (nil nil nil) ...) instead, ie, only clump nils?

Interesting idea. With the current implementation of partition-by I
don�t see that this is possible. I made minimal changes to that function
after which I can do this:
(defn group-nils [coll]
   (let [i (.iterator (range 20))]
     (partition-by #(or (nil? %) (.next i)) coll)))

(group-nils '(a a b c nil nil nil d e f))
==> ((a) (a) (b) (c) (nil nil nil) (d) (e) (f))

Note, group-nils will not work with the partition-by that currently
is checked in into clojure.contrib.seq-utils.
Instead it will run into an endless loop.
As Rich Hickey demands contributers to first sign an agreement before
he accepts their code I won�t post my patch here. But people with
some Clojure knowledge should be able to modify partition-by slightly
to make it possible:
http://code.google.com/p/clojure-contrib/source/browse/trunk/src/clojure/contrib/seq_utils.clj#70


Andr�
-- 
Lisp is not dead. It�s just the URL that has changed:
http://clojure.org/
From: TomSW
Subject: Re: counting nils in a list
Date: 
Message-ID: <a72d0b95-0191-434f-a4b7-429a8e421efa@a39g2000yqc.googlegroups.com>
On Mar 15, 3:38 am, André Thieme <address.good.until.
···········@justmail.de> wrote:

> Interesting idea. With the current implementation of partition-by I
> don’t see that this is possible. I made minimal changes to that function
> after which I can do this:
> (defn group-nils [coll]
>    (let [i (.iterator (range 20))]
>      (partition-by #(or (nil? %) (.next i)) coll)))
>
> (group-nils '(a a b c nil nil nil d e f))
> ==> ((a) (a) (b) (c) (nil nil nil) (d) (e) (f))
>
> Note, group-nils will not work with the partition-by that currently
> is checked in into clojure.contrib.seq-utils.
> Instead it will run into an endless loop.

I noticed that also in some of my "subtle" ways to reintroduce state,
eg
(partition-by #(or (nil? %) (gensym)) coll)
- why does it happen?

A less elegant version that works with the existing partition-by:
(map #(map second %)
           (partition-by #(when (second %) (first %))
                         (indexed
                          '(a a b c nil nil nil d e f))))

cheers,
Tom
From: André Thieme
Subject: Re: counting nils in a list
Date: 
Message-ID: <gpip7a$tkj$1@news.motzarella.org>
TomSW schrieb:
> On Mar 15, 3:38 am, Andr� Thieme <address.good.until.
> ···········@justmail.de> wrote:
> 
>> Interesting idea. With the current implementation of partition-by I
>> don�t see that this is possible. I made minimal changes to that function
>> after which I can do this:
>> (defn group-nils [coll]
>>    (let [i (.iterator (range 20))]
>>      (partition-by #(or (nil? %) (.next i)) coll)))
>>
>> (group-nils '(a a b c nil nil nil d e f))
>> ==> ((a) (a) (b) (c) (nil nil nil) (d) (e) (f))
>>
>> Note, group-nils will not work with the partition-by that currently
>> is checked in into clojure.contrib.seq-utils.
>> Instead it will run into an endless loop.
> 
> I noticed that also in some of my "subtle" ways to reintroduce state,
> eg
> (partition-by #(or (nil? %) (gensym)) coll)
> - why does it happen?

Hey, cool idea! Nice gensym trick :)

Okay, why does it happen? Let�s look at the implementation of
partition-by:
...
(let [fv (f (first s))
       run (take-while #(= fv (f %)) s)]
...

s is a sequence of our collection.
f is the function we provided partition-by.
fv is the first value - f applied to the first element of our seq.
Now the next var RUN is set.
We take as many objects out of s starting (and including again) at
(first s) as long f applied to those values equals fv.
Typically, if we provide a function without side effects to partition-by
this is fine. (f (first s)) will always have the same result. But you
and I provided functions that are not referentially transparent.
When (f (first s)) is bound to fv then it has a different value, the
new result of (gensym), than before. This results in take-while
returning an empty lazy-seq, which gets bound to run.

Now in the last line of partition-by we have:
(cons run (partition-by f (drop (count run) s)))))))

Here we count how many objetcs run holds. It�s zero. Although it should
be at least one, (first s). So drop will drop zero elements from the
collection and call partition-by again, with the unchanged sequence.
This is the endless loop.

I personally would argue that this is a bug in partition-by.
run should contain fv as a minimum, and the take-while should not run on
s but on its rest. This will make sure that run always contains at least
one element. Also this can slightly improve the performance, when f has
a longer runtime.

But even if we say that partition-by should not function correctly in
general, when it gets passed a function with side effects, then the
doc strings is misleading:
"Applies f to each value in coll, splitting it each time f returns
  a new value.  Returns a lazy seq of lazy seqs."


Andr�
-- 
Lisp is not dead. It�s just the URL that has changed:
http://clojure.org/
From: André Thieme
Subject: Re: counting nils in a list
Date: 
Message-ID: <gphps8$ea1$2@news.motzarella.org>
Andr� Thieme schrieb:

> (defn group-nils [coll]
>   (let [i (.iterator (range 20))]
>     (partition-by #(or (nil? %) (.next i)) coll)))

Posted too early, sorry. It should be:
(let [i (.iterator (iterate inc 0))]


Andr�
-- 
From: William James
Subject: Re: counting nils in a list
Date: 
Message-ID: <gpja5p012ao@enews4.newsguy.com>
William James wrote:

> Pascal J. Bourguignon wrote:
> 
> > 
> > (defun cut-list-if (predicate list)
> >   (loop
> >      :with results = '()
> >      :with sublist = '()
> >      :for (a b) :on list
> >      :do (if (funcall predicate a b)
> >            (progn
> >              (push a sublist)
> >              (push sublist results)
> >              (setf sublist '()))
> >            (push a sublist))
> >      :finally (when sublist (push sublist results)) (return (reverse results))))
> 
> Ruby:
> 
> 
> def cut_if list
>   result = []
>   sublist = []
>   list.each_index{|i|
>     a,b = list[i,2]
>     if yield( a, b )
>       result << (sublist << a)
>       sublist = []
>     else   sublist << a    end }
>   if sublist.empty? then  result else result << sublist end
> end

Shorter:

def cut_if list
  result = []
  sublist = []
  list.each_index{|i|
    a,b = list[i,2]
    sublist << a
    if yield( a, b )
      result << sublist
      sublist = []
    end }
  if sublist.empty? then  result else result << sublist end
end
From: Kenneth Tilton
Subject: Re: counting nils in a list
Date: 
Message-ID: <49bdb2bd$0$20303$607ed4bc@cv.net>
William James wrote:
> William James wrote:
> 
>> Pascal J. Bourguignon wrote:
>>
>>> (defun cut-list-if (predicate list)
>>>   (loop
>>>      :with results = '()
>>>      :with sublist = '()
>>>      :for (a b) :on list
>>>      :do (if (funcall predicate a b)
>>>            (progn
>>>              (push a sublist)
>>>              (push sublist results)
>>>              (setf sublist '()))
>>>            (push a sublist))
>>>      :finally (when sublist (push sublist results)) (return (reverse results))))
>> Ruby:
>>
>>
>> def cut_if list
>>   result = []
>>   sublist = []
>>   list.each_index{|i|
>>     a,b = list[i,2]
>>     if yield( a, b )
>>       result << (sublist << a)
>>       sublist = []
>>     else   sublist << a    end }
>>   if sublist.empty? then  result else result << sublist end
>> end
> 
> Shorter:
> 
> def cut_if list
>   result = []
>   sublist = []
>   list.each_index{|i|
>     a,b = list[i,2]
>     sublist << a
>     if yield( a, b )
>       result << sublist
>       sublist = []
>     end }
>   if sublist.empty? then  result else result << sublist end
> end

I find it delightful that you are so befuddled by Rubby that you offer 
as shorter that which is longer as you try to figure out how to code 
something so simple in repeated posts to a newsgroup in which you are 
posing as somehow knowledgable. About anything.

Can't wait for your third try.

kenny