3 ms·
> does occasionally feel like functions aren't truly first-class in a lisp-2 The definition of 'first class functions' is not a feeling, but three capabilities
by lispm 9y ago
> does occasionally feel like functions aren't truly first-class in a lisp-2
The definition of 'first class functions' is not a feeling, but three capabilities:
CL-USER 9 > (let ((sin-fn (function sin)))
(list
; 1) passing functions as arguments to other functions
(mapcar sin-fn '(1 2 3 4))
; 2) returning them as the values from other functions
((lambda () sin-fn))
; 3) and assigning them to variables or storing them in data structures
(let ((v #(1 2 3)))
(setf (aref v 1) sin-fn)
v)))
((0.84147096 0.9092974 0.14112 -0.7568025) ; 1)
#<Function SIN 410007BC14> ; 2)
#(1 #<Function SIN 410007BC14> 3)) ; 3)
As you can see, functions are first-class values in Common Lisp.
> In most lisps passing functions as arguments is just as common as "calling" non-function values is in Clojure
Including Lisp-2s. Passing functions is completely normal and widely used in Common Lisp. The Common Lisp standard has literally zillions of functions where you pass one or more functions in.
Common Lisp also can make CLOS objects callable.
- db48x 9y agoYou've made my point for me. The very fact that you must write (function sin), or #'sin, or use funcall is a way that it treats functions differently than normal values. Since it requires some amount of extra though and/or typing, this often seen as a bad thing. Compare Scheme, Clojure, or other lisp-1s where if you want to pass the sin function to someone, you just say sin. That whole outer let vanishes in those languages, and the result is much simpler. And just as we both agree that in Common Lisp passing functions in as arguments is very common, so in Clojure is "calling" a vector on a number to index into it, or "calling" a symbol to use it as an index into a alist or hash table, etc. Not only do you not have to type anything extra, you can treat all values as callable.
- lispm 9y ago> The very fact that you must write (function sin), or #'sin, or use funcall is a way that it treats functions differently than normal values. Look closer. I have not used FUNCTION in 1), 2) or 3). Common Lisp does not treat functions different from other values. They are first class values. These are the three operations which define whether functions are first class values: ( https://en.wikipedia.org/wiki/First-class_function https://en.wikipedia.org/wiki/First-class_function ) : 1) passing a function 2) returning a function 3) assigning them to variables or storing them in data structures None of that requires anything special for functions in Common Lisp. What you need to do in Common Lisp, is to use FUNCTION to get a function from a lexical name and you need to call such a function via FUNCALL, but that has nothing to do with the requirements for a 'first class datatype', which is defined by the three requirements above (passing, returning, assigning).
- db48x 9y ago> What you need to do in Common Lisp, is to use FUNCTION to get a function from a > lexical name and you need to call such a function via FUNCALL, but that has nothing > to do with the requirements for a 'first class datatype', which is defined by the > three requirements above (passing, returning, assigning). And I'm saying that in practice, regardless of any technical definitions you'll find in a textbook, this need to treat functions specially is exactly what makes people who learn Common Lisp wonder why people say that functions are first class values. You don't have to look up the value of a variable by writing (variable foo), but you do have to use (function foo). Clojure goes one step further and lets you treat non-functions as if they were functions, by using them in the function positions of expressions.
- lispm 9y ago> regardless of any technical definitions you'll find in a textbook It's the definition of first-class values. You may have your own, but then you need to tell us what you mean first. Communication by redefining established terms is getting painful... > why people say that functions are first class values Because you can pass functions, return functions and store functions. That's what "first-class datatype" means. > You don't have to look up the value of a variable by writing (variable foo), but you do have to use (function foo) Only if you want to get the function from the function namespace. If the function is already referenced in the value namespace, then you don't have to do it. > Clojure goes one step further and lets you treat non-functions as if they were functions, by using them in the function positions of expressions. Which existed long before Clojure in Lisp. For example Lisp Machine Lisp had callable arrays 4 decades ago. Features like these make it a good write-only language.
- db48x 9y ago> Communication by redefining established terms is getting painful... And here I thought I was telling you that not everybody uses "first-class" (or even "first-class values") in precisely the same way. I agree that the strictest definition only deals with how you use the various types of values you might have in your program, and not with the types of names you can give them. I hope you can also agree that not everyone limits themselves to just the values; they see the differences in how functions get stored in the environment, and recalled from it, and see this as treating the functions differently than the variables. This does mean that many people are operating with a broader definition of what "first-class" means. It would be perfectly clear to call it "first-class naming", for example, but polysemy is not unique to software engineering; we must allow for it in all fields of endeavour. My only point all along was merely that when someone hyperbolically calls Common Lisp a "Jim Crow" language, they are not wrong merely because they are talking about names instead of values. As an aside, I didn't mean to imply that Clojure invented callable arrays, merely that Clojure programs use them frequently; probably just as frequently as they use higher-order functions. I take no position on whether any language is "write-only" or not; that would be nearly as productive as talking about "virtue signalling". ;)
- kbp 9y ago> The very fact that you must write (function sin), or #'sin, or use funcall is a way that it treats functions differently than normal values. It doesn't treat functions differently from other values. You can say (defvar fn (lambda (x) (+ x 2))) and put a function in a value cell if you want, and then to pass it to a function you just say fn, same as if it were a non-function value. The distinction you're talking about is about symbols being treated differently depending on context, not anything about functions being treated differently from other values.
- db48x 9y agoI'm perfectly well aware that the difference is only in how names are resolved into values, and not in the values themselves. This is a distinction that doesn't matter to most people. What they care most about is what they have to type to convince the compiler to do what they want, and when there are exceptional circumstances that make them think harder or remember more details.
- lispm 9y agoTelling explicitly what one wants to do actually helps the compiler and it helps with the maintenance. The compiler then can help me to find calls which are just accidents, name clashes, etc. In a Lisp-2 in the expression (sin 2) then SIN is always a function name. It can't be anything else. It's not possible to bind a name in the function namespace to a non-function (or macro). Using something like FUNCALL is a clear sign that a function value is being called. This makes the source code longer, but it helps me to understand the code even months/years later.
- db48x 9y agoPersonally I don't think the distinction between Lisp-1 and Lisp-2 is a very important one, in terms of practical engineering. I just wish I could use any Lisp more often; Lisp-1 vs Lisp-2 doesn't really enter in to it. Now, I have to go back to working on this Automake/Autoconf mess I'm working on. mumble mumble M4 mumble...
- kazinator 9y agoIn my TXR Lisp, which is a Lisp-2 dialect with strong ties to Common Lisp, I reveal a design which gives the programmer all of the advantages of Lisp-1, without losing Lisp-2 and its advantages. http://www.nongnu.org/txr/txr-manpage.html#N-02DC9E04 http://www.nongnu.org/txr/txr-manpage.html#N-02DC9E04
- flavio81 9y ago> The very fact that you must write (function sin), or #'sin, or use funcall is a way that it treats functions differently than normal values. Since it requires some amount of extra though and/or typing, this often seen as a bad thing. What a silly thing to say. The reason you need to put "#'" in Common Lisp to indicate that you are referring to a function, is because in CL functions have their own namespace. So "#'" tells Lisp that you are referring to a symbol that is inside the function namespace. Otherwise, no "#'" and Lisp will look at it on the regular namespace. Conversely, if you prefix a symbol with ":", such as in ":this :that :foo :bar", the ":" means that this symbol resides on the keyword namespace. Thus, in Common Lisp you can have a function named "foo", a variable named "foo", a keyword named "foo" as well with no conflict. It has NOTHING to do with functions being or not being "first class citizens".