←back to thread

110 points jackdaniel | 1 comments | | HN request time: 0s | source
Show context
adamddev1 ◴[] No.44972696[source]
Ah, in an alternate world where Brendan Eich wasn't pressured by his superiors to make JS more Java-like, we could have had something like this as very normal.

I wonder how much faster that would have pushed the world into FP ideas. While sometimes I prefer the bracket/C syntax, I wonder how things would have evolved if JS was a lisp originally. Instead of things moving to TypeScript, would they be moving to something like typed Lisp or OCaml, or PureScript ?

replies(5): >>44973351 #>>44973702 #>>44976138 #>>44976751 #>>44977298 #
umanwizard ◴[] No.44973702[source]
Is CL really particularly more “functional” than JavaScript? I don’t know CL but I know it bears some passing similarity to Emacs Lisp, which is usually written in a pretty imperative style. Sure, it has first-class closures but so does JS.
replies(6): >>44973781 #>>44973976 #>>44974501 #>>44975807 #>>44976563 #>>44984186 #
1. tmtvl ◴[] No.44984186[source]
CL is pretty multi-paradigm. To give the boring 'double all numbers in a list' example:

  (defun double-numbers (numbers)
    "Doubles a list of NUMBERS.
  Docstring and type declarations are optional."
    (declare (type List numbers))
    (mapcar (lambda (x)
              (declare (type Number x))
              (* x 2))
            numbers))

  (defun double-numbers (numbers)
    (labels ((accumulate-loop (nums acc)
                (if (null nums)
                    (funcall acc nums)
                    (destructuring-bind (first-number &rest other-numbers)
                        nums
                      (accumulate-loop other-numbers
                                       (lambda (result)
                                         (funcall acc
                                                  (cons (* first-number 2)
                                                        result))))))))
      (accumulate-loop numbers (lambda (result) result))))

  (defun double-numbers (numbers)
    (if (null numbers)
        numbers
        (cons (* (first numbers) 2)
              (double-numbers (rest numbers))))

  (defun double-numbers (numbers)
    (loop :for number :in numbers
          :collect (* number 2)))

  (defun double-numbers (numbers)
    (if (null numbers)
        numbers
        (prog ((remaining-numbers (rest numbers))
               (first-pair (list (* (first numbers) 2)))
               last-pair)
          (setf last-pair first-pair)
        :start-loop
          (when (null remaining-numbers)
            (return first-pair))
          (setf (rest last-pair)
                (list (* (pop remaining-numbers) 2)))
          (setf last-pair (rest last-pair))
          (go :start-loop))))
And that's before going into libraries like SERIES or iterate. There are, of course, benefits and disadvantages (readability, performance, some CL implementations don't do TCO,...) to every option, but generally CL lets you code in any way you want (you could even write some macros to let you write it using more infix or postfix style syntax, but I don't see the appeal of doing so).