Search code examples
lispslime

Lisp - Functions passed into another function as arguments and called from within a Let


I am learning Lisp and, just for practice/education, am trying to define a function that will

  1. ask the user to enter a number until they enter an integer > 0 [copied from Paul Graham's Ansi Common Lisp]

  2. print that number and subtract 1 from it, repeat until the number hits 0, then return.

I am trying to do this via passing 2 functions into a higher-order function - one to get the number from the user, and another recursive [just for fun] function that prints the number while counting it down to 0.

Right now my higher-order function is not working correctly [I've tested the first 2 and they work fine] and I cannot figure out why. I am using SBCL in SLIME. My code for the 3 functions looks like this:

(defun ask-number ()
  (format t "Please enter a number. ")
  (let ((val (read))) ; so val is a single-item list containing the symbol 'read'?
    (cond             ; no here read is a function call
      ((numberp val)
       (cond
     ((< val 0) (ask-number))
     (T val)))
      (t (ask-number))))))

(defun count-down (n)
  (cond
    ((eql n 0) n)
    (t
     (progn
       (format t "Number is: ~A ~%" n)
       (let ((n (- n 1)))
       (count-down n))))))

(defun landslide (f1 f2)
  (let (x (f1))
    (progn
      (format t "x is: ~A ~%" x)
      (f2 x)))))

but calling slime-eval-defun in landslide yields:

; SLIME 2.27; in: DEFUN LANDSLIDE
;     (F1)
; 
; caught STYLE-WARNING:
;   The variable F1 is defined but never used.

;     (SB-INT:NAMED-LAMBDA LANDSLIDE
;         (F1 F2)
;       (BLOCK LANDSLIDE
;         (LET (X (F1))
;           (PROGN (FORMAT T "x is: ~A ~%" X) (F2 X)))))
; 
; caught STYLE-WARNING:
;   The variable F1 is defined but never used.
; 
; caught STYLE-WARNING:
;   The variable F2 is defined but never used.
; in: DEFUN LANDSLIDE
;     (F2 X)
; 
; caught STYLE-WARNING:
;   undefined function: COMMON-LISP-USER::F2
; 
; compilation unit finished
;   Undefined function:
;     F2
;   caught 4 STYLE-WARNING conditions

I have tried several [what I consider] obvious modifications to the code, and they all fail with different warnings. Calling the function like (landslide (ask-number) (count-down)), ask-number prompts for user input as expected, but then SLIME fails with

invalid number of arguments: 0
   [Condition of type SB-INT:SIMPLE-PROGRAM-ERROR]

I know I have to be missing something really obvious; can someone tell me what it is?


Solution

  • First: You are missing a set of parens in your let:

    You have (let (x (f1)) ...) which binds 2 variables x and f1 to nil.

    What you want is (let ((x (f1))) ...) which binds 1 variable x to the values of function call (f1)

    Second: Common Lisp is a "lisp-2", so to call f2 you need to use funcall: (funcall f2 ...).

    Finally: all your progns are unnecessary, and your code is hard to read because of broken indentation, you can use Emacs to fix it.