From: synthespian
Subject: [newbie] Help with loop, progn
Date: 
Message-ID: <beo93c$7atg4$1@ID-78052.news.uni-berlin.de>
Hello --

  I'm having trouble with this simple function. I'm supposed to input
(write-dna-seq 10) and it should evaluate to a sequence of length 10 
chosen randomly from the set {A, T, G, C}.
  I've writen other variations, but I can't get it right.
  I can't see where the flaw is...


  (defun write-dna-seq (seq-size)
               (let ((control-var seq-size))
                 (loop
                    (if (zerop control-var) 'end)
                    (progn
                     (setq variable (random 5))
                      (cond ((= variable 1) (princ 'A))
                            ((= variable 2) (princ 'G))
                            ((= variable 3) (princ 'T))
                            ((= variable 4) (princ 'C)) (t))
                      (decf control-var)))))

  I get an infinite output of ATCGAGTT...
  What is the problem? The let? The progn?

  I appreciate any help given.
  Thanks very much in advance.

  Regs,

  HL

From: Matthew Danish
Subject: Re: [newbie] Help with loop, progn
Date: 
Message-ID: <20030712071605.GR17568@lain.mapcar.org>
On Sat, Jul 12, 2003 at 03:13:48AM -0300, synthespian wrote:
> Hello --
> 
>  I'm having trouble with this simple function. I'm supposed to input
> (write-dna-seq 10) and it should evaluate to a sequence of length 10 
> chosen randomly from the set {A, T, G, C}.
>  I've writen other variations, but I can't get it right.
>  I can't see where the flaw is...
> 
>  (defun write-dna-seq (seq-size)
>               (let ((control-var seq-size))
>                 (loop
>                    (if (zerop control-var) 'end)
>                    (progn
>                     (setq variable (random 5))
>                      (cond ((= variable 1) (princ 'A))
>                            ((= variable 2) (princ 'G))
>                            ((= variable 3) (princ 'T))
>                            ((= variable 4) (princ 'C)) (t))
>                      (decf control-var)))))
> 
>  I get an infinite output of ATCGAGTT...
>  What is the problem? The let? The progn?

A lot.  You are using basic LOOP, which always loops forever (until you,
presumably, make a control-transfer out of it).  Saying (if (zerop
control-var) 'end) doesn't really do anything.  Perhaps you mean (if
(zerop (control-var) (return-from write-dna-seq 'end))).  Next, what is
VARIABLE?  You never declared it, so you cannot just use SETQ on it.
How about this:

(defun write-dna-seq (seq-size &optional (stream *standard-output*))
  "Writes a DNA sequence of length seq-size to the given stream.  DNA
  sequence consists of characters chosen from (A T G C)"
  (loop repeat seq-size do
        (princ (aref #(A G T C) (random 4))
               stream)
  ;; Return value not important
  (values)))
        
-- 
; Matthew Danish <·······@andrew.cmu.edu>
; OpenPGP public key: C24B6010 on keyring.debian.org
; Signed or encrypted mail welcome.
; "There is no dark side of the moon really; matter of fact, it's all dark."
From: Nick Levine
Subject: Re: [newbie] Help with loop, progn
Date: 
Message-ID: <8732fc48.0307120516.5e8b2ce@posting.google.com>
This wouldn't be a homework assignment, would it?

The reason that the loop never terminates is that you haven't RETURNed
from it. Look this up:
http://www.lispworks.com/reference/HyperSpec/Body/m_return.htm

The next problem you're going to face is that your code can't
"evaluate to a sequence", because you're not generating a sequence.
(You are PRINTing a number of characters. That's not the same thing.)
Look up PUSH:
http://www.lispworks.com/reference/HyperSpec/Body/m_push.htm

Or better still, consider (LOOP REPEAT... COLLECT ...), as that will
stylishly solve both problems in one go.
http://www.lispworks.com/reference/HyperSpec/Body/06_aca.htm
http://www.lispworks.com/reference/HyperSpec/Body/06_ada.htm

Futher points to note: RANDOM returns a non-negative integer, so why
not call (RANDOM 4) and taylor the CASE statement to accepting zero?
Also, given the "execution" forms in the case statement all look the
same, why not replace the whole thing with an AREF into the string
"ATGC"?

Finally, there is nothing wrong with the LET (other than that you
won't need to bind CONTROL-VAR if you use LOOP ... REPEAT), and the
PROGN is superfluous but not doing any harm.

All the best,

- nick


>   I'm having trouble with this simple function. I'm supposed to input
> (write-dna-seq 10) and it should evaluate to a sequence of length 10 
> chosen randomly from the set {A, T, G, C}.
>   I've writen other variations, but I can't get it right.
>   I can't see where the flaw is...
> 
> 
>   (defun write-dna-seq (seq-size)
>                (let ((control-var seq-size))
>                  (loop
>                     (if (zerop control-var) 'end)
>                     (progn
>                      (setq variable (random 5))
>                       (cond ((= variable 1) (princ 'A))
>                             ((= variable 2) (princ 'G))
>                             ((= variable 3) (princ 'T))
>                             ((= variable 4) (princ 'C)) (t))
>                       (decf control-var)))))
> 
>   I get an infinite output of ATCGAGTT...
>   What is the problem? The let? The progn?
> 
>   I appreciate any help given.
>   Thanks very much in advance.
> 
>   Regs,
> 
>   HL
From: synthespian
Subject: Re: [newbie] Help with loop, progn
Date: 
Message-ID: <bepo2e$7uvu3$1@ID-78052.news.uni-berlin.de>
Nick Levine wrote:
> This wouldn't be a homework assignment, would it?

  No, not homework. It's very slow-paced self-study, squeezing CL in the 
late-night stretches, due to other study topics - I'm
not from CS).
  Thanks to you and Matthew Danish. I shall go now and deeply
reflect on my mistakes and your answers, and return to the pile of
books that will lead me away from newbieland. :-) At least, there was 
nothing wrong with let.
  Above all, thanks for all the pointers.

  Best regards

  Henry
From: synthespian
Subject: Re: [newbie] Help with loop, progn
Date: 
Message-ID: <beq4ce$7vmnm$1@ID-78052.news.uni-berlin.de>
Nick Levine wrote:
> This wouldn't be a homework assignment, would it?
> 
> The reason that the loop never terminates is that you haven't RETURNed
> from it. Look this up:
> http://www.lispworks.com/reference/HyperSpec/Body/m_return.htm

  Fixed that.
> 
> The next problem you're going to face is that your code can't
> "evaluate to a sequence", because you're not generating a sequence.
> (You are PRINTing a number of characters. That's not the same thing.)
> Look up PUSH:
> http://www.lispworks.com/reference/HyperSpec/Body/m_push.htm
> 
  I don't really understand what you mean.
  Do you mean that I should send it to a stream, as someone else (M.D.) 
suggested? Do you mean it so that that another function can reuse the 
output of the write-dna-seq? That's what I wanted...

> Or better still, consider (LOOP REPEAT... COLLECT ...), as that will
> stylishly solve both problems in one go.
> http://www.lispworks.com/reference/HyperSpec/Body/06_aca.htm
> http://www.lispworks.com/reference/HyperSpec/Body/06_ada.htm
> 
  Ah, (loop...collect) is really the simplest construct! Kind of like in 
pther languages. I'd forgotten about it (the LOOP chapter in the 
HyperSpec is kinda huge, isn't it?)

> Futher points to note: RANDOM returns a non-negative integer, so why
> not call (RANDOM 4) and taylor the CASE statement to accepting zero?
> Also, given the "execution" forms in the case statement all look the
> same, why not replace the whole thing with an AREF into the string
> "ATGC"?

  I just wanted to use a more traditional control structure.
> 
> Finally, there is nothing wrong with the LET (other than that you
> won't need to bind CONTROL-VAR if you use LOOP ... REPEAT), and the
> PROGN is superfluous but not doing any harm.

I fixed the function, now:
  (defun write-dna-seq (seq-size)
               (loop
                (if (zerop seq-size) (return 'end))
               	 (progn
                   (let ((variable (random 4)))
                      (cond ((= variable 0) (princ 'A))
                            ((= variable 1) (princ 'G))
                            ((= variable 2) (princ 'T))
                            ((= variable 3) (princ 'C)) (t))
                      (decf seq-size)))))

  The thing is I wanted to use PROGN to see if I understood. In the 
above code, the PROGN is in the "ELSE" clause of the IF conditional. It 
isn't necessary. I noticed also that if leave the DECF form /outside/ of 
the LET form, as in the version bellow, (in fact, outside the ELSE 
clause), the code still evaluates correctly, proving in fact that "loop 
is an implicit PROGN":

      (defun write-dna-seq-1 (seq-size)
               (loop
                (if (zerop seq-size) (return 'end))
                   (let ((variable (random 4)))
                      (cond ((= variable 0) (princ 'A))
                            ((= variable 1) (princ 'G))
                            ((= variable 2) (princ 'T))
                            ((= variable 3) (princ 'C)) (t)))
                      (decf seq-size)))

  Thanks to all who helped me out.

  Best regards,

  Henry

> 
> All the best,
> 
> - nick
> 
> 
> 
>>  I'm having trouble with this simple function. I'm supposed to input
>>(write-dna-seq 10) and it should evaluate to a sequence of length 10 
>>chosen randomly from the set {A, T, G, C}.
>>  I've writen other variations, but I can't get it right.
>>  I can't see where the flaw is...
>>
>>
>>  (defun write-dna-seq (seq-size)
>>               (let ((control-var seq-size))
>>                 (loop
>>                    (if (zerop control-var) 'end)
>>                    (progn
>>                     (setq variable (random 5))
>>                      (cond ((= variable 1) (princ 'A))
>>                            ((= variable 2) (princ 'G))
>>                            ((= variable 3) (princ 'T))
>>                            ((= variable 4) (princ 'C)) (t))
>>                      (decf control-var)))))
>>
>>  I get an infinite output of ATCGAGTT...
>>  What is the problem? The let? The progn?
>>
>>  I appreciate any help given.
>>  Thanks very much in advance.
>>
>>  Regs,
>>
>>  HL
From: Gareth McCaughan
Subject: Re: [newbie] Help with loop, progn
Date: 
Message-ID: <87y8z348u5.fsf@g.mccaughan.ntlworld.com>
"synthespian" wrote:

>> The next problem you're going to face is that your code can't
>> "evaluate to a sequence", because you're not generating a sequence.
>> (You are PRINTing a number of characters. That's not the same thing.)
>> Look up PUSH:
>> http://www.lispworks.com/reference/HyperSpec/Body/m_push.htm
>
>   I don't really understand what you mean.
>   Do you mean that I should send it to a stream, as someone else
> (M.D.) suggested? Do you mean it so that that another function can
> reuse the output of the write-dna-seq? That's what I wanted...

Well, you could send it to a stream. But using something like
LOOP with COLLECT is much simpler. The key point is that instead
of spewing things to the output you should think in terms of
building a data structure containing those things. If you
anticipate having truly vast strings of bases, some other
approach might work better -- e.g., make your function take
an extra argument that's a function to be called on each newly
chosen base -- but I bet you don't need that here.

> > Futher points to note: RANDOM returns a non-negative integer, so why
> > not call (RANDOM 4) and taylor the CASE statement to accepting zero?
> > Also, given the "execution" forms in the case statement all look the
> > same, why not replace the whole thing with an AREF into the string
> > "ATGC"?
> 
>   I just wanted to use a more traditional control structure.

Why? :-)

(And if you're after traditional control structures, why
on earth use something so primitive as this for an ordinary
"repeat N times" thing? We have extended LOOP. We have DO.
We have DOTIMES. But despite all this richness you've
chosen to write in the style you'd be forced into if you
were programming in, say, an impoverished version of BASIC
that's had the FOR keyword removed...

> I fixed the function, now:
>   (defun write-dna-seq (seq-size)
>                (loop
>                 (if (zerop seq-size) (return 'end))
>                  (progn
>                    (let ((variable (random 4)))
>                       (cond ((= variable 0) (princ 'A))
>                             ((= variable 1) (princ 'G))
>                             ((= variable 2) (princ 'T))
>                             ((= variable 3) (princ 'C)) (t))
>                       (decf seq-size)))))
> 
>   The thing is I wanted to use PROGN to see if I understood. In the
> above code, the PROGN is in the "ELSE" clause of the IF
> conditional. It isn't necessary.

The PROGN is not in the ELSE clause. If that's what you
intended, then you should lose the rparen on the same line
as the IF and move it to the end. So your indentation is
misleading.

Anyway, the PROGN would be redundant *wherever* you put it,
because what's inside it is a *single form*. For any form FOO,
(PROGN FOO) is exactly the same as FOO. (Er, perhaps there
are some obscure exceptions, though I can't think of any
right now.)

Oh, something else that isn't necessary is your final (T)
in the COND. It's unnecessary for two reasons. Firstly,
one of the non-default cases will always happen. Secondly,
even if they didn't, the behaviour of COND when all the
conditions fail is to do nothing and return NIL, just the
same as (T) would make it do. When you were choosing random
numbers from {0,1,2,3,4} there was perhaps something to be
said for making it explicit what happens in the default
case, but not any more.

>                                  I noticed also that if leave the DECF
> form /outside/ of the LET form, as in the version bellow, (in fact,
> outside the ELSE clause), the code still evaluates correctly, proving
> in fact that "loop is an implicit PROGN":
> 
>       (defun write-dna-seq-1 (seq-size)
>                (loop
>                 (if (zerop seq-size) (return 'end))
>                 (let ((variable (random 4)))
>                    (cond ((= variable 0) (princ 'A))
>                          ((= variable 1) (princ 'G))
>                          ((= variable 2) (princ 'T))
>                          ((= variable 3) (princ 'C)) (t)))
>                 (decf seq-size)))

(I've fixed up the indentation.) That was in fact already shown
by the code in the first function: the IF and the PROGN were
both part of the loop body.

(defun random-base () (aref "AGTC" (random 4)))
(defun random-bases (n) (loop repeat n collect (random-base)))
(defun write-random-bases (n) (mapc #'write-char (random-bases n)))

-- 
Gareth McCaughan
.sig under construc
From: Marco Antoniotti
Subject: Re: [newbie] Help with loop, progn
Date: 
Message-ID: <3F11A660.7060109@cs.nyu.edu>
(defun make-random-dna-sequence (length)
    (let ((new-seq (make-array length
                               :initial-element #\a
                               :element-type '(member #\a #\c #\g #\t))))
       (dotimes (i length new-seq)
          (let ((r (random 1.0)))
             (cond ((<= r 0.25) (setf (aref new-seq i) #\a))
                   ((<= r 0.50) (setf (aref new-seq i) #\c))
                   ((<= r 0.75) (setf (aref new-seq i) #\g))
                   ((<= r 1.00) (setf (aref new-seq i) #\t))
                   )))))

(defun write-dna-seq (seq &optional (stream *standard-output*))
   (format stream "~A" seq))

(defun print-random-dna-seq (length &optional (stream *standard-outut))
   (write-dna-seq (make-random-dna-sequence length stream)))






synthespian wrote:
> Hello --
> 
>  I'm having trouble with this simple function. I'm supposed to input
> (write-dna-seq 10) and it should evaluate to a sequence of length 10 
> chosen randomly from the set {A, T, G, C}.
>  I've writen other variations, but I can't get it right.
>  I can't see where the flaw is...
> 
> 
>  (defun write-dna-seq (seq-size)
>               (let ((control-var seq-size))
>                 (loop
>                    (if (zerop control-var) 'end)
>                    (progn
>                     (setq variable (random 5))
>                      (cond ((= variable 1) (princ 'A))
>                            ((= variable 2) (princ 'G))
>                            ((= variable 3) (princ 'T))
>                            ((= variable 4) (princ 'C)) (t))
>                      (decf control-var)))))
> 
>  I get an infinite output of ATCGAGTT...
>  What is the problem? The let? The progn?
> 
>  I appreciate any help given.
>  Thanks very much in advance.
> 
>  Regs,
> 
>  HL
>