Where I stand on Lisp
So, Lisp. It's been on my radar for years and I'm finally getting around to learning it. The syntax is foreign but I find I'm having the most difficulty in the areas of semantics and the standard library. The symbol semantics are giving me tremendous trouble for sure, mainly because I find it hard to tell when a symbol is needed as opposed to a value. It probably sounds silly, but I find C pointers to be more intuitive and straightforward, and this is probably owed to the fact that C is exclusively pass-by-value, whereas Lisp is ostensibly both pass-by-value and pass-by-reference, and the semantics therein--which behavior is chosen and when--is unknown to me. For example, why is (1 2 3)
inappropriate in a situation where '(1 2 3)
and list
--assuming its value is (1 2 3)
--are perfectly okay? Ostensibly, this is an ambiguity in the syntax and Lisp thinks I'm trying to call a function called 1
. This type of situation stresses me out precisely because I start thinking of the unknown unknowns--what other situations like this are going to come along and derail me or cause bugs that remain hidden for extended periods of time? I imagine, perhaps without warrant, disasters on par with Undefined Behavior in C.
The code to be reviewed
Long intro, but since this is a code review, I feel it should probably be made clear where I stand so that reviews can take it into account and use it to more effectively communicate the review. I.e. I am a seasoned programmer, I dabble in "language lawyering", and I'm a complete beginner in Lisp.
That said, my first Common Lisp project is FizzBuzz. And what better way to get more comfortable with the language than to put my newbie code out for other people to systematically tear apart?
#|| divisible()
|| I don't usually write functions for something as obvious as
|| "is X divisible by Y", but in this case, I find
||
|| (divisible 15 5)
||
|| easier to read than
||
|| (= 0 (mod 15 5))
||
|| feel free to refute if you disagree and think this is a
|| code smell or you know of a more idiomatic way
||
|| Also feel free to say something if you feel
|| this C-like multi-line style is in bad taste
||#
(defun divisible (a b) (= 0 (mod a b)))
#|| range()
|| Copy/pasted from somewhere else. I don't know what cons does
|| I do understand that the function is recursive
|| I do not think I would have thought of this on my own
||#
(defun range (min max)
(when (<= min max)
(cons min (range (+ min 1) max))))
(defun fizzbuzz (n)
(setf out (string ""))
(unless (or (divisible n 3) (divisible n 5))
(return-from fizzbuzz n))
(when (divisible n 3)
(setf out (format nil "~d~d" out "Fizz")))
(when (divisible n 5)
(setf out (format nil "~d~d" out "Buzz")))
out)
(setf 1to100 (range 1 100))
(setf 1to100fb (map 'list #'fizzbuzz 1to100))
(mapcar #'(lambda (str) (format t "~d~%" str)) 1to100fb)
I admit, it's hard to break away from imperative programming.
The style isn't completely foreign to me, actually. I've already used (and am very much a fan of) style similar to this in C-like languages...
while(condition)
if(condition)
do_something;
And I'm already a fan of functional programming...
return list.map(x => (x * x) % 256).filter(x => x >= 10);
So I believe I'm on the right track. Although Dunning-Kruger is always in effect.