Helpful List Function

Started by Jeremy Dunn, June 12, 2007, 07:38:32 PM

Previous topic - Next topic

Jeremy Dunn

One thing I always love about LISP is that it always gets you thinking in ever more general terms after you start out with something simple. Here is a good example of it. My starting point was a one-liner that I wrote that is pretty much self-explanatory:



(define (length? lst n)(= (length lst) n))



Can't get much simpler than that. I don't know how many times I wrote (= (length lst) n) before thinking of it. Just like the paper clip. But what about greater abstraction? What do we do with that length once we get it? I find that I either use it in a control structure to branch the program or I use it in a calculation. Let us just consider the control structure aspect of it. Here is the code first:



(define (iflength lst (n 0) X Y Z , i flg)
  (setq i (length lst) flg (= i n))
  (if Z (if (< i n) X flg Y Z)
      Y (if flg X Y)
      X (if flg X)
      flg
))


So what does iflength do? iflength gobbles up the previous function and acts as a control structure too. Let i be the length of the list, n the number we are comparing to the list, lst the list itself and X,Y,Z are code chunks to be executed depending on how a boolean test is performed. So it goes like this, if we write



(iflength lst n X Y Z) - if i<n then X is executed elseif i=n then Y is executed else Z is executed.

(iflength lst n X Y) - if i=n then X is executed else Y is

(iflength lst n X) - if i=n then X is executed else nothing happens

(iflength lst n)  - behaves the same as the length? function



Very simple, very handy.

rickyboy

#1
I see what you're trying to do, but you won't get iflength to work the way you want without defining it as a macro.  Happy coding!  --Ricky
(λx. x x) (λx. x x)

Jeff

#2
It will work if you pass it a quoted list that happens to be an expression.  But it should be a macro.
Jeff

=====

Old programmers don\'t die. They just parse on...



http://artfulcode.net\">Artful code

newdep

#3
I like this function.. a nice alternative for a lenght check..perhpas even

more logical too ;-)
-- (define? (Cornflakes))

Jeff

#4
Here's a macro that will do it:


(define-macro (if-length _list-n _expr-true _expr-nil)
  "Tests length of list (_list-n 0) against integer value (_list-n 1) for
  equality.  If true, evaluates _expr-true; else, evaluates _expr-nil.  Does
  simple type checking on _list-n's elements."
  (let ((lst (eval (_list-n 0))) (n (eval (_list-n 1))))
       ;; Throw error if we get bad data types
       (unless (list? lst) (throw-error "List expected in if-length"))
       (unless (integer? n) (throw-error "Integer expected in if-length"))
       (if (= n (length lst))
           (if _expr-true (eval _expr-true))
           (if _expr-nil (eval _expr-nil)))))

(set 'a '(a b c d))
(if-length (a 4))
(if-length (a 4)
           (println "List is 4 items long."))
(if-length (a 5)
           (println "List is 5 items long.")
           (println "List is not 5 items long."))


It does simple type checking and accepts parameters in the idiomatic way for if-style control structures.  I haven't tested it too much, though.
Jeff

=====

Old programmers don\'t die. They just parse on...



http://artfulcode.net\">Artful code

Jeremy Dunn

#5
You're so right guys, define-macro indeed. This is what happens when you are too enthusiastic and have been working overtime for a couple of weeks. This one works a bit better



(define-macro (iflength lst n do-X do-Y do-Z)
  (setq L   (if do-Z 5 do-Y 4 do-X 3 n 2 1)
        i   (length (eval lst))
        n   (abs n)
        flg (= i n)
  )
  (if (lessthanorequal 1 L 5)
      (if (= L 5)(eval (if (< i n) do-X flg do-Y do-Z))
          (= L 4)(eval (if flg do-X do-Y))
          (= L 3)(eval (if flg do-X))
          (= L 2) flg
          (= i)
      )
  )
)