Re: Beginner - Function Critique
- From: Pascal Bourguignon <spam@xxxxxxxxxxxxxxxx>
- Date: Fri, 30 Sep 2005 18:57:26 +0200
crystal1 <crystal1@xxxxxxxxxxxx> writes:
> See below. These functions have been created a thousand times and are
> trivial, but I wrote these instances myself and am a pretty proud
> beginner. What do you think?
>
> A week ago recursion was still pretty hazy, but a after reading
> "Common Lisp, An Interactive Approach" the progress has been
> steady. What a great book.
>
> ;;;;;;;;;;;;;;;;
>
> (defpackage :string-utils
> (:use :common-lisp))
>
> (in-package :string-utils)
>
> (defun line-split1 (s d)
> "Helper function for LINE-SPLIT. Return a list with elements of
> supplied string S up to the first instance of delimiter D as :STRING
> and the remaining string after the delimiter as :REMAINDER."
> (if (position d s) (list :string (subseq s 0 (position d s))
> :remainder (subseq s (1+ (position d s))))
> (list :string s :remainder "")))
(defun line-split1 (s d)
(if (position d s)
(values (subseq s 0 (position d s))
(subseq s (1+ (position d s))))
(values s "")))
> (defun line-split (s d)
> "Return a list of substrings in string S when delimited by delimiter D."
> (check-type s string)
> (check-type d character)
These check-types are done by called functions, so you're doing them twice.
> (if (= (length s) 0) '()
> (cons (getf (line-split1 s d) :string)
> (line-split (getf (line-split1 s d) :remainder) d))))
Indent it this way:
(if condition
then
else)
otherwise we will believe your else is a then!
Note that you're calling twice line-split1 with the same argument!
(defun line-split (s d)
"Return a list of substrings in string S when delimited by delimiter D."
(if (= (length s) 0)
'()
(multiple-value-bind (string remainder) (line-split1 s d)
(cons string (line-split remainder d)))))
Note that this is still a non-terminal recursive function, so you'll
need a lot of stack space.
You could try to write a recursive function that is tail-recursive, to
give a chance to a TCO implementation. Note that not all CL
implementations do TCO, so you still may want to write an iterative solution.
> (defun read-file (filename delimiter)
> "Return a list of lists containing strings in pathname FILENAME
> delimited by character DELIMITER."
> (let ((output '()))
> (with-open-file (in filename)
> (do ((line (read-line in nil) (read-line in nil)))
> ((null line))
> (push (line-split line delimiter) output))
> (nreverse output))))
Good. Eventually, I switched to loop:
(defun read-file (filename delimiter)
"Return a list of lists containing strings in pathname FILENAME
delimited by character DELIMITER."
(with-open-file (in filename)
(loop
:for line = (read-line in nil)
:while line
:collect (line-split line delimiter))))
> (defmacro join-strings (&rest strings)
> "Return the result of concatenating the supplied strings."
> `(concatenate 'string ,@strings))
You don't need a macro here. With a macro, you cannot write:
(mapcar 'join-string '("A " "The " "Some ")
'("cat " "dog " "guy ")
'("eats " "bites " "runs ")
'("." "." "."))
Write it as a function. If you want, you can declare it INLINE.
> (defun rjust (s w)
> "Right justify string S by W spaces."
> (rjust1 s (- w (length s))))
>
> (defun rjust1 (s w)
> "Helper function for RJUST."
> (if (<= w 0) s
> (join-strings (rjust1 s (1- w)) " ")))
You can use local functions:
(defun rjust (s w)
"Right justify string S by W spaces."
(labels ((rjust1 (s w)
(if (<= w 0)
s
(join-strings (rjust1 s (1- w)) " "))))
(rjust1 s (- w (length s)))))
> (defun ljust (s w)
> "Left justify string S by W spaces."
> (ljust1 s (- w (length s))))
>
> (defun zfill (s w)
> "Left justify string S by W 0 characters."
> (ljust1 s (- w (length s)) "0"))
>
> (defun ljust1 (s w &optional (c " "))
> "Helper function for LJUST."
> (if (<= w 0) s
> (join-strings c (ljust1 s (1- w) c))))
Don't you feel that there's some redundancy here?
What about an API such as:
(defun string-pad (string width &key (padchar " ") (justification :left))
...)
(string-pad "123" 10 :padchar #\0 :justification :right)
(string-pad "Hello" 10 :padchar #\!)
(string-pad "BIG TITILE" 20 :justification :center)
Overall, congratulations for your lisping! Go on on this journey!
--
__Pascal Bourguignon__ http://www.informatimago.com/
Nobody can fix the economy. Nobody can be trusted with their finger
on the button. Nobody's perfect. VOTE FOR NOBODY.
.
- References:
- Beginner - Function Critique
- From: crystal1
- Beginner - Function Critique
- Prev by Date: Re: macro question
- Next by Date: Re: Beginner - Function Critique
- Previous by thread: Re: Beginner - Function Critique
- Next by thread: Re: Beginner - Function Critique
- Index(es):