Added additionnal variants with check-type.

Pascal J. Bourguignon [2017-04-11 18:58]
Added additionnal variants with check-type.
Filename
p02.lisp
diff --git a/p02.lisp b/p02.lisp
index 2c55183..0d47733 100644
--- a/p02.lisp
+++ b/p02.lisp
@@ -37,4 +37,60 @@ P02 (*) Find the last but one box of a list.
     (t                          (last list 2))))


+
+
+;; We test and signal an error when the list is too short (the
+;; specifications asks for at least 2 boxes (cons cells).  We could
+;; use CHECK-TYPE with a type specification corresponding to lists of
+;; at least to cons cells:
+
+(defun my-but-last (list)
+  (check-type list (cons t (cons t t)))
+  (if (endp (cddr list))
+      list
+      (my-but-last (cdr list))))
+
+
+;; Now we may consider that checking the list at each recursive call
+;; would be expensive (and useless).  Indeed, in general, checking the
+;; arguments needs to be done only on public entry points (module
+;; APIs), while internal functions can assume that their
+;; preconditions, their arguments, and the global invariants of their
+;; module are valid.  We may use LABELS to define internal recursive
+;; functions (FLET if they're not recursive):
+
+(defun my-but-last (list)
+  (check-type list (cons t (cons t t)))
+  (labels ((find-but-last (list)
+             (if (endp (cddr list))
+                 list
+                 (find-but-last (cdr list)))))
+    (find-but-last list)))
+
+;; We are using endp to test and signal an error on dotted-lists such
+;; as (a b c . d).  But the problem statement didn't strictly exclude
+;; them.  One may argue that "list" covers dotted-lists, circular
+;; lists as well as proper-lists.  Furthermore, the only constraint is
+;; that there are two cons cells, nothing is said about the contents
+;; of the CDR slot of the last cons cell.  Therefore we may use ATOM
+;; to test for cdr of the last cons cell, or the negation, CONSP if we
+;; exchange the branches of the IF:
+
+(defun my-but-last (list)
+  (check-type list (cons t (cons t t)))
+  (labels ((find-but-last (list)
+             (if (consp (cddr list))
+                 (find-but-last (cdr list))
+                 list)))
+    (find-but-last list)))
+
+
+
+;; Note: we would use check-type on functions close to the user,
+;; typically, functions given user data, so that the user may be able
+;; to substite a correct and meaningful value for a bad value.  But
+;; functions in deeper code should probably directly signal an error
+;; notably when they process massaged internal data that the user may
+;; not recognize (and would be in pain to correct meaningfull).
+
 ;;;; THE END ;;;;
ViewGit