6 ms·
There's only one definition that matters: functional programming is programming with mathematical (pure) functions. As a consequence you get referential transp
by bad_user 10y ago
There's only one definition that matters: functional programming is programming with mathematical (pure) functions.
As a consequence you get referential transparency and thus equational reasoning. But change this definition and the term becomes meaningless.
- kibwen 10y agoThough by this definition, Lisp, the granddaddy of functional programming languages, is not a functional programming language.
- catnaroek 10y agoIt indeed isn't. Here's my litmus test. Is 2^100 always equal to 2^100? Let's ask SBCL: * (eq (expt 2 100) (expt 2 100)) NIL Damn object identities, ruining muh equalities. (Disclaimer: I'm not saying functional programming is the right approach for writing every program, but if a language can't even get arithmetic and relational operators right...)
- junke 10y agoStructural equivalence is given by EQUALP and has of course its own limitations (but works with trees, user-defined structs and hash-tables, for example). Of course, if you use the identity comparison, you get different results. I agree CL does not fit your definition of functional programming. An implementation is permitted to make "copies" of characters and numbers at any time. The effect is that Common Lisp makes no guarantee that eq is true even when both its arguments are "the same thing" if that thing is a character or number. http://www.lispworks.com/documentation/lw51/CLHS/Body/f_eq.htm http://www.lispworks.com/documentation/lw51/CLHS/Body/f_eq.h...
- catnaroek 10y agoI'm aware of EQUALP. But the problem remains that it's possible to distinguish between supposedly “equal” values. Lisp and Scala are first and foremost object-oriented languages - whatever values you want to manipulate are always subordinate to objects whose physical identity in memory matters in the language's semantics, no matter how irrelevant they might be for your problem domain. On the other hand, in Haskell and ML, due to their superior value-oriented design, there's no way to distinguish between “this 123456789” and “that 123456789”, or between “this list [1,2,3]” and “that list [1,2,3]”. There is only one number 123456789 and one one list [1,2,3] in the language's semantics, no matter how many copies of their representation might exist in memory.
- junke 10y agoI am also aware of that. I am not really trying to convince you of anything, mostly trying to prevent casual readers from being taught Common Lisp from you. Look at the example you just gave, this is beyond ridiculous. I would prefer if you were focusing on what you want to fight "for", not what you want to fight "against". You like having a strong separation between the language and its implementation. I get it. Note however that if you are the Haskell compiler, you can know things the programmer cannot, or you can inject code that can perform manipulations the programmer cannot express. There probably is an identity equality operator down there, that people cannot access. If you like that, I can understand; I can understand the appeal for a strict separation of concerns and the desire to express only the high-level intent. But really, I think this is not much different in CL and that you are focusing on implementation details. In CL the separation is not enforced, and that is your main problem with it. The CL compiler is defined at the language specification level. You have access to internals, by choice, just as if you were writing Haskell ASTs using an Haskell compiler's internal API. As such, you can cross abstraction barriers whenever you need. We already discussed about this once, you can use purely functional data-structures (see FSET) and EQUALP and code to that functional interface and pretend there is no computer down there. Then, if you want, you can play with packages and symbols to make MAP & co. refer to the parallel version (see LPARALLEL), re-compile and have parallel code (this works best with unqualified symbols and different package definitions for the same file). In all PL discussions, there is eventually mention of an hypothetical sufficiently smart compiler. The CL point of view is (among other things) that such a compiler is one where a programmer can easily add its own extensions. That allows you to express the intent of the program clearly in one place and have the implementation details elsewhere.
- catnaroek 10y ago> Note however that if you are the Haskell compiler, you can know things the programmer cannot, or you can inject code that can perform manipulations the programmer cannot express. Those would be implementation details, not part of the language itself. Hence... > There probably is an identity equality operator down there, that people cannot access. ... this doesn't make sense. > You have access to internals, by choice, just as if you were writing Haskell ASTs using an Haskell compiler's internal API. However, there's no way to portably manipulate compiler internals in Haskell. Heck, Haskell syntax, unlike Lisp syntax, can actually be represented in multiple ways: named variables, de Bruijn indices and levels, HOAS, etc. And this is a good thing. > In all PL discussions, there is eventually mention of an hypothetical sufficiently smart compiler. I wouldn't have brought it up myself. > The CL point of view is (among other things) that such a compiler is one where a programmer can easily add its own extensions. There's no dichotomy between extensibility and abstraction enforcement, even if you try to set up one.
- kazinator 10y agoI don't see how support for multiple equalities makes something not a functional language. Functional doesn't mean "the semantics of everything is tied to its printed syntax" so that if two things look the same in the syntax, they denote the same thing. (Right?) Suppose we take Haskell and give it an equal operator which can tell that two bignums are different instances and not equal. Does it cease being functional? What if we don't use that operator anywhere in a program and don't even know it exists; how do we know the language is not functional?
- catnaroek 10y ago> Functional doesn't mean "the semantics of everything is tied to its printed syntax" so that if two things look the same in the syntax, they denote the same thing. (Right?) I don't care about syntax. I want to manipulate the values I care about, not object identities. I want to operate on numbers, strings, lists, trees, what have you. Not memory cells that allegedly contain representations of numbers, strings, lists, trees, what have you. This is strictly a semantic issue. > I don't see how support for multiple equalities makes something not a functional language. FWIW, what most languages call “physical” or “reference equality” is a special case of structural equality (which is always the prior notion). Structural equality of mutable cells (which have dedicated types in Haskell and ML) happens to be physical equality. > Suppose we take Haskell and give it an equal operator which can tell that two bignums are different instances and not equal. Does it cease being functional? Yes. > What if we don't use that operator anywhere in a program and don't even know it exists; how do we know the language is not functional? Then you're doing functional programming in a non-functional language.
- deleted 10y ago[deleted]
- junke 10y ago> What if we don't use that operator anywhere in a program and don't even know it exists; how do we know the language is not functional? ;-) If a tree falls in a forest and no one is around to hear it, does it make a sound? If a program satisfies a property but the compiler cannot prove it, can we still rely on it?
- lispm 10y agoWell, I would just use EQL. If you want to use Haskell, use Haskell. Common Lisp works differently.
- bad_user 10y agoThe original LISP was influenced by Alonzo Church's lambda calculus, see: https://dl.acm.org/citation.cfm?id=367199 https://dl.acm.org/citation.cfm?id=367199 - however if you'll study its history the first Lisps were only experiments and for example they didn't have lexical scoping, but dynamic scoping. The Lisp descendant that made FP doable was Scheme, bringing lexical scoping and call/cc. And today's Common Lisp is definitely not Scheme, or an FP language. You can do FP in CLisp of course, since it's quite capable, but CLisp is a general purpose language and is used as such. And in my small experience from playing with it, there isn't much FP in CLisp, but YMMV. Lisp in general is a big family. Emacs Lisp for example has absolutely nothing to do with FP. Of course you can romanticize about Lisp and it definitely has some cool descendants like Clojure, but you know, don't do it too much :-)