Re: Question about design, defmacro, macrolet, and &environment

From: Damien Kick (dkick1_at_email.mot.com)
Date: 11/17/03

  • Next message: Edi Weitz: "Re: Question about design, defmacro, macrolet, and &environment"
    Date: 16 Nov 2003 18:52:47 -0600
    
    

    Well, some more style questions...

    ;; This was the first version. It uses tail recursion. This is a
    ;; very Scheme-ish style. I wonder how long it will take someone on
    ;; c.l.l to propose a version of EXPECT-STRING that uses LOOP. As
    ;; I've been introduced to CL by Graham's _ANSI Common Lisp_, I have
    ;; been introduced to an anti-LOOP cl-view and appreciate having been
    ;; introduced to a pro-LOOP view by c.l.l. However, I'm still not
    ;; comfortable with LOOP and wish I knew of a tutorial for it.
    (defun expect-string--rec (string stream &key (echo t))
      (labels ((lemma (string in end match echo pos)
                 ;; If/when CMU CL allows one to trace local functions, I
                 ;; will be able to remove the following WHEN.
                 (when *trace-expect-string-lemma*
                   (format t "expect-string lemma ~A~%"
                           (list string in end match echo pos)))
                 (unless (= pos end)
                   (let ((actual (read-char in))
                         (expect (char string pos)))
                     (write-char actual match)
                     (when echo
                       (write-char actual echo)
                       (force-output echo))
                     (let ((next (if (char= actual expect)
                                     (1+ pos)
                                     0)))
                       (lemma string in end match echo next))))))
        (values string
                (let ((end (length string))
                      (echo (synonym-value echo t *standard-output*)))
                  (with-output-to-string (match)
                    (lemma string stream end match echo 0))))))

    ;; I've rewritten the function to use DO instead of recursion.
    (defun expect-string (string stream &key (echo t))
      "Expects to find the literal STRING on the STREAM."
      (values string
              (let ((end (length string))
                    (echo (synonym-value echo t *standard-output*)))
                (with-output-to-string (match)
                  (do ((actual)
                       (pos 0 (if (char= actual (char string pos))
                                  (1+ pos)
                                  0)))
                      ((= pos end))
                    ;; Okay, I know that I shouldn't be bothered by the
                    ;; SETQ, by I still am. So, I try a couple different
                    ;; versions. Are any of the variations worth the
                    ;; effort? Probably not.
                    (setq actual (read-char stream))
                    (write-char actual match)
                    (when echo
                      (write-char actual echo)
                      (force-output echo)))))))

    ;; Remove the need for the explicit SETQ by doing all of the work in
    ;; the step forms. However, now we need to use EQL to test the actual
    ;; character read against the expected character because ACTUAL will
    ;; be NIL the first time through.
    (defun expect-string-1 (string stream &key (echo t))
      (values string
              (let ((end (length string))
                    (echo (synonym-value echo t *standard-output*)))
                (with-output-to-string (match)
                  ;; Using the LAMBDA form allows me to achieve the side
                  ;; effects as part of the step form of ACTUAL.
                  (do ((actual nil (funcall #'(lambda (x)
                                                (write-char x match)
                                                (when echo
                                                  (write-char x echo)
                                                  (force-output echo))
                                                x)
                                            (read-char stream)))
                       ;; Because ACTUAL will be NIL in the first pass, we
                       ;; use EQL instead of CHAR=. Is this potentially
                       ;; slower?
                       (pos 0 (if (eql actual (char string pos))
                                  (1+ pos)
                                  0)))
                      ((= pos end)))))))

    ;; Uses DO* instead of DO. Because of this, we know that ACTUAL will
    ;; be assigned before the test performed in the step form of POS, and
    ;; so we do not need to handle a case in which ACTUAL may be NIL. Of
    ;; course, I've read that DO* is frequently considered to be bad
    ;; style, and so I want to be suspisious about it. However, it kind
    ;; of doesn't really look all that bad. What am I missing? Would a
    ;; LOOP version be better than all of these?
    (defun expect-string-2 (string stream &key (echo t))
      (values string
              (let ((end (length string))
                    (echo (synonym-value echo t *standard-output*)))
                (with-output-to-string (match)
                  ;; Again, use the LAMBDA form to achieve the side
                  ;; effects in the step form.
                  (do* ((actual nil (funcall #'(lambda (x)
                                                 (write-char x match)
                                                 (when echo
                                                   (write-char x echo)
                                                   (force-output echo))
                                                 x)
                                             (read-char stream)))
                        ;; Because we know that ACTUAL will be assigned
                        ;; before this point, we can use CHAR= as ACTUAL
                        ;; will never be NIL.
                        (pos 0 (if (char= actual (char string pos))
                                   (1+ pos)
                                   0)))
                       ((= pos end)))))))


  • Next message: Edi Weitz: "Re: Question about design, defmacro, macrolet, and &environment"

    Relevant Pages

    • Re: Can not find older posting: Reading files (fast)
      ... |> "Sucks up an entire file from PATH into a freshly-allocated string, ... (loop for bytes-read = (read-sequence buffer file-stream) ... CHARACTER; or a type specifier for a finite recognizable subtype of INTEGER; or one of the symbols SIGNED-BYTE, UNSIGNED-BYTE, or ... (loop for line = (read-line s nil nil) ...
      (comp.lang.lisp)
    • Re: Strings .each method
      ... It is kind of hard to explain but I have a long string that someone ... want to pass the words between two tags as a value for the javascript. ... What I am trying to do is add a while loop inside the block that will ... "words" nil ...
      (comp.lang.ruby)
    • Re: File I/O & String conversion - CLISP
      ... (let ((main-list nil)) ... First let's do the outer LOOP: ... (loop for line = (read-line in nil) ... of LOOP to walk each LINE character by character, with STRING ...
      (comp.lang.lisp)
    • Re: File I/O & String conversion - CLISP
      ... (let ((main-list nil)) ... First let's do the outer LOOP: ... (loop for line = (read-line in nil) ... of LOOP to walk each LINE character by character, with STRING ...
      (comp.lang.lisp)
    • Re: Programming challenge
      ... (loop for a from 0 to 1 do ... (with-output-to-string (out string) ... (loop for c = (peek-char nil stream nil nil) ...
      (comp.lang.lisp)