Author Topic: Bottom-up design  (Read 927 times)

0 Members and 1 Guest are viewing this topic.

JohnK

  • Administrator
  • Seagull
  • Posts: 10626
Bottom-up design
« on: February 28, 2023, 09:55:55 AM »
Bottom-up programming is essentially about simplifying the interface you program in (-i.e. Lisp can be altered by defining functions which can alter the programming methods you use).

For example: Instead of defining/designing functions like this:

Code - Auto/Visual Lisp: [Select]
  1. ; Main function: behave
  2. (defun behave (animal)
  3.   (cond
  4.     ((eq animal 'dog)
  5.      (dog
  6.        (mapcar 'eval '(wag-tail bark))))
  7.     ((eq animal 'pig)
  8.      (pig (mapcar 'eval '(rut oink))))
  9.     ;...

which are difficult to extend, debug, read, and use we can make our code easier to use by adopting the bottom-up programming mythology.

I will demonstrate how to do bottom-up design, but first we need a few simple functions which you can use throughout this tutorial.

Code - Auto/Visual Lisp: [Select]
  1. ; Simple functions common to all below.
  2. (defun wag-tail () (princ "wag, wag."))
  3. (defun bark () (princ "woof, woof."))
  4. (defun rut () (princ "roll in mud."))
  5. (defun oink () (princ "oink, oink."))
  6. (defun rub-legs () (princ "trip owner."))
  7. (defun scratch-carpet () (princ "destroy owner's stuff."))

We are used to setting up a function(s) that looks like this:

Code - Auto/Visual Lisp: [Select]
  1. ; Main function: behave
  2. (defun behave (animal)
  3.   (cond
  4.     ((eq animal 'dog)
  5.      (dog
  6.        (mapcar 'eval '(wag-tail bark)))
  7.          )
  8.     ((eq animal 'pig)
  9.      (pig (mapcar 'eval '(rut oink)))
  10.          )
  11.     ((eq animal 'cat)
  12.      (cat (mapcar 'eval '(rub-legs scratch-carpet)))
  13.          )
  14.     )
  15.   (princ)
  16.   )
  17.  
  18. ; Support function: dog
  19. (defun dog (behavior)
  20.   (mapcar
  21.     (function
  22.       (lambda (behavior)
  23.         (eval (list behavior))))
  24.     behavior)
  25.   )
  26.  
  27. ; Support function: pig
  28. (defun pig (behavior)
  29.   (mapcar
  30.     (function
  31.       (lambda (behavior)
  32.         (eval (list behavior))))
  33.     behavior)
  34.   )
  35.  
  36. ; Support function: cat
  37. (defun cat (behavior)
  38.   (mapcar
  39.     (function
  40.       (lambda (behavior)
  41.         (eval (list behavior))))
  42.     behavior)
  43.   )

Usage:

Code - Auto/Visual Lisp: [Select]
  1. (behave 'dog)
  2. (behave 'pig)
  3. (behave 'cat)

As you can see we start off designing the `behave` function to do something we want based on certain conditions. We can call `behave` to something different based on the condition we give (-i.e. behave like a Dog/Pig/Cat/etc.). This code works but is not very flexible if we need to add a condition like "owl", "horse" or "mouse" or etc.. To add functionality, we'd need to build support functions and modify the main function `behave`. The amount of maintenace needed to extend the tool is entirely wasteful and can be avoided if we utilize bottom-up programming.

For example, It can be more flexible if we built the `behave` function more generically and supplied the methods we want to preform. Like the revision below (NOTE: below I am using SET instead of DEFUN, but there is no difference in operation between SET and DEFUN when used like this, only used to highlight and introduce). This simple redesign of the `behave` function will allow us to extend the conditions and cut down on maintenace time and mistakes.

Code - Auto/Visual Lisp: [Select]
  1. (defun behave (animal behavior)
  2.   (eval (list animal (quote behavior)))
  3.   (princ)
  4.   )
  5.  
  6. (set 'dog
  7.      (lambda (behavior)
  8.        (mapcar
  9.          (function
  10.            (lambda (behavior)
  11.              (eval (list behavior))))
  12.          behavior)))
  13.  
  14. (set 'pig
  15.      (lambda (behavior)
  16.        (mapcar
  17.          (function
  18.            (lambda (behavior)
  19.              (eval (list behavior))))
  20.          behavior)))
  21.  
  22. (set 'cat
  23.      (lambda (behavior)
  24.        (mapcar
  25.          (function
  26.            (lambda (behavior)
  27.              (eval (list behavior))))
  28.          behavior)))

Usage:

Code - Auto/Visual Lisp: [Select]
  1. ; Now you can call `behave` like this:
  2. (behave 'dog '(wag-tail bark))
  3. (behave 'pig '(rut oink))
  4. (behave 'cat '(rub-legs scratch-carpet))

This simple redesign allows us to create as many `animals` and `behaviors` as we'd like and this redesign is a lot like using "methods" in "Object Orientated programming" (OOP) which is what bottom-up programming is about (we can change how we USE lisp). By using this method we essentially define--on the fly--what methods are sent to the `behave` function instead of using the predefined list.

A word about why I used SET instead of DEFUN in the last example. This is a on-going developing quirk of personal preference. In this case, I think of `dog`, `pig`, and `cat` as more of a `symbol` with a `method` then a full fledged `function` with an `operation`. I believe the use of DEFUN may be faster but again this is more of a personal preference thing. However the SET functions have a type of USUBR instead of SUBR if that means anything to you.

Back to the bottom-up discussion; as you can see, we had to change the parameter list to the `behave` function and it's not quite as user friendly and as readable as the first example. Also, it still has the potential to support mistakes in coding so, we can rectify these short-comings by adding another function definition to build the functions based on the given arguments and thus make things a bit more user friendly and readable.

Code - Auto/Visual Lisp: [Select]
  1. ; Define a simpler version of `behave`
  2. (defun behave (animal)
  3.   (eval (list animal))
  4.   (princ)
  5.   )
  6.  
  7. ; Build a function generator helper.
  8. (defun define (binding body)
  9.   (set
  10.     binding
  11.     (eval
  12.       (append
  13.         (list 'lambda nil)
  14.         (mapcar 'list body)
  15.         )
  16.       )
  17.     )
  18.   )

Usage:

Code - Auto/Visual Lisp: [Select]
  1. ; Define what the dog function should be.
  2. (define 'dog '(wag-tail bark))
  3. (define 'pig '(rut bark))
  4. (define 'cat '(rub-legs scratch-carpet))
  5.  
  6. ; call the behave function.
  7. (behave 'dog)
  8. (behave 'pig)
  9. (behave 'cat)

With a little bit of setup--one helper function--we can change the way we use the language (-i.e. to be more clear) with very little overhead.

This also has the added benefit of making things easier to debug (can you spot my mistake; I'll give you a hint: silly pig).

NOTE: according to my benchmarks this method also gives you a SLIGHT increase in speed of operation but that shouldn't be the major take away from the use of our `method like` design.
TheSwamp.org (serving the CAD community since 2003)
Member location map - Add yourself

Donate to TheSwamp.org

pkohut

  • Bull Frog
  • Posts: 483
Re: Bottom-up design
« Reply #1 on: February 28, 2023, 11:51:45 AM »

A word about why I used SET instead of DEFUN in the last example. This is a on-going developing quirk of personal preference. In this case, I think of `dog`, `pig`, and `cat` as more of a `symbol` with a `method` then a full fledged `function` with an `operation`. I believe the use of DEFUN may be faster but again this is more of a personal preference thing. However the SET functions have a type of USUBR instead of SUBR if that means anything to you.

Pretty nice overall example and thanks for clarifying the usage of SET.  :smitten:
New tread (not retired) - public repo at https://github.com/pkohut

kdub_nz

  • Mesozoic keyThumper
  • SuperMod
  • Water Moccasin
  • Posts: 2132
  • class keyThumper<T>:ILazy<T>
Re: Bottom-up design
« Reply #2 on: February 28, 2023, 02:19:47 PM »

Nice discussion point John.

without meaning to distract from the theme ;
In your set statements I mentally translated 'behaviour' to 'action' . . . but a rose by any name is still a rose
Called Kerry in my other life
Retired; but they dragged me back in !

I live at UTC + 13.00

---
some people complain about loading the dishwasher.
Sometimes the question is more important than the answer.

VovKa

  • Water Moccasin
  • Posts: 1629
  • Ukraine
Re: Bottom-up design
« Reply #3 on: February 28, 2023, 04:46:29 PM »
i vote for associations lists

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8691
  • AKA Daniel
Re: Bottom-up design
« Reply #4 on: February 28, 2023, 05:22:43 PM »
i vote for associations lists
like ((0 . dog)(1 . bark)(2 . eat))?

VovKa

  • Water Moccasin
  • Posts: 1629
  • Ukraine
Re: Bottom-up design
« Reply #5 on: February 28, 2023, 05:45:08 PM »
like ((0 . dog)(1 . bark)(2 . eat))?
or
Code: [Select]
(setq animals (list (list 'dog
  (list 'properties 'fluffy 'friendly 'noisy)
  (list 'abilities 'wag-tail 'bark 'bite)
    )
    (list 'cat
  (list 'properties 'fluffy 'unfriendly 'silent)
  (list 'abilities 'lick-tail 'meow 'bite)
    )
      )
)
(setq abilities (list (list 'wag-tail '(princ "wag, wag"))
      (list 'lick-tail '(princ "lick, lick"))
      (list 'bark '(princ "woof, woof"))
      (list 'meow '(princ "meow, meow"))
      (list 'bite '(princ "yam, yam"))
)
)