5 ms·
I think Lisp is the best all-rounder. If it isn't the best at something, you can MAKE it the best.
by qwertyuiop924 10y ago
I think Lisp is the best all-rounder. If it isn't the best at something, you can MAKE it the best.
- jomamaxx 10y agoLisp as a 'language' maybe, but the problem is it's more than syntax and compiler. The advantage of JVM, garbage collection, relative platform neutrality, docs that are really consistent, libraries that are very easily shared, and the huge amount of things built into the lang package over time, the number of Q/A on Stack Overflow, resources available, support, 3rd part libraries - these are things that Lisp really lacks, making it not a very useful thing all around.
- qwertyuiop924 10y agoIt depends on what lisp you pick. And while CL isn't my favorite, if you're a Common Lisp user, some of that stuff's already there for you. But yeah, the JVM is a great platform. But Java is inseparable from it, and Java isn't a great language.
- _asummers 10y agoLisp and JVM are not mutually exclusive, of course. There were JVM Lisps before Clojure (I don't know any off the top of my head), but Clojure is an extremely nice language to work with, if you've never worked with it.
- catnaroek 10y agoCould you tell me how to eliminate the notion of object identity from Lisp when it's unwanted? (FWIW, “just don't use eq” isn't good enough advice, because you can just mutate one of two supposedly “equal” objects to observe the difference between them.) This is crucial to make functional programming work.
- qwertyuiop924 10y ago>Could you tell me how to eliminate the notion of object identity from Lisp when it's unwanted? So by "object identity," you mean doing equality comparisons with pointers instead of actually value equality. Just don't use eq. Use equal instead. >FWIW, “just don't use eq” isn't good enough advice, because you can just mutate one of two supposedly “equal” objects to observe the difference between them Yeah, that's true of every programming language in existance. What, do you want every equal object to be mutated, along with the one you mutated? That's just crazy talk. >This is crucial to make functional programming work. Well, if you're doing FP, than you aren't mutating values anyway. So just don't use eq. At this point, your question utterly baffles me. Come back with a better explanation, or some examples of what you want, and I'll try to give you a better answer.
- catnaroek 10y ago> So by "object identity," you mean doing equality comparisons with pointers instead of actually value equality. Just don't use eq. Use equal instead. The problem goes further than that. “equal” doesn't really mean equal - it only means equal until the next mutation. Not very helpful in a language with unrestricted mutation. > Yeah, that's true of every programming language in existance. It isn't true in ML or Haskell. In those languages, mutation is strictly opt-in, on a per-type basis. When you don't use mutation, equality is by value. When you use mutation, equality is by object identity. You can't “accidentally distinguish” between two copies of the same immutable value. > What, do you want every equal object to be mutated, along with the one you mutated? That's just crazy talk. I want to distinguish between objects meant to be mutated and values not meant to. > Well, if you're doing FP, than you aren't mutating values anyway. So just don't use eq. If I'm doing functional programming, I want to mutate as little as possible, but certain things require mutation to be done efficiently. What I want is the language to help me distinguish between functional values and imperative objects. (0) ML: If you attempt to mutate a value, you get a compile-time error. (1) Racket: If you attempt to mutate a value, you get a runtime error. Pretty sensible in a dynamic language. (2) Common Lisp: Only primitives are values, and mutating anything else is permitted.
- lispm 10y ago
- junke 10y agoAre there people saying that you can't implement Common Lisp in OCaml/Haskell, with heterogeneous structures, dynamically typed and so on? You certainly can, but that's not an easy task. If your language does not support natively the set of rules you really like to enforce, you can still work in a style you like provided you establishes conventions and abstractions around it. So if you were actually interested in developing with, say, purely functional collections in Common Lisp, you would use the FSET[0] library: (equalp (fset:bag 1 2) (fset:bag 1 2)) T (equalp (fset:bag 1 2) (fset:bag 2 1)) T That's exactly the same approach that people use when they do "C with classes", by reifying the abstraction into the host language. Unsurprisingly, data-structures in FSET are implemented as Common Lisp structures, which allows having read-only slots as well as type specifiers. Since we only want to have read-only slots, let's define a wrapper around defstruct (http://pastebin.com/30D6BnRg http://pastebin.com/30D6BnRg): (deftype tree () '(or node null leaf)) (deft leaf data) (deft node (left nil :type tree) (right nil :type tree)) (equalp (node (node (leaf 3) (leaf 4)) nil) (node (node (leaf 3) (leaf 4)) nil)) => T (compile nil (lambda () (setf (data (leaf 3)) 0))) ; compilation unit finished ; Undefined function: ; (SETF DATA) ; caught 1 STYLE-WARNING condition (compile nil (lambda () (node "strange" "node"))) ; caught WARNING: ; Constant ; "strange" conflicts with its asserted type ; (OR COMMON-LISP-USER::NODE NULL COMMON-LISP-USER::LEAF). ; See also: ; The SBCL Manual, Node "Handling of Types" The above messages are caught while compiling the functions, not when calling them. The language specification does not give you another way to mutate structure slots other than opt-in accessors. Granted, your implementation is probably smart enough to let you mutate it with (SETF SLOT-VALUE), but as a CL developer, you know that its bad to use it and that you should rely on accessors provided by the API. The advantage of Lisp at this point is that you can wrap your abstraction so tightly that it is indistinguishable from core features. But maybe that's not enough for you, because there are not enough checks and you have your own idea of how things should work and you think you should do more compilation and less interpretation. The compiler is available right here too, so you can even use it from your own compiler (during macroexpansion if you need) and do the analyzes you like. Or, you can even output a completely different executable file. Then you code a compiler in your new language because that's what grown-up languages do. So, in order to do ML in Lisp, you develop your own DSL, an interpreter and later you bootstrap a compiler which is then self-sufficient to exist alone. That's roughly what happened decades ago: "Edinburgh LCF, including the ML interpreter, was implemented in Lisp"[1][2]. ACL2, an applicative, side-effect free subset of Common Lisp used for first-order theorem proving (Boyer-Moore), shares the same approach. But the language that exists now, even though it does perfectly what it was designed for, is not Lisp anymore, and can't do exactly the things we actually like to do in Common Lisp. [0] https://common-lisp.net/project/fset/Site/index.html https://common-lisp.net/project/fset/Site/index.html [1] https://ocaml.org/learn/history.html https://ocaml.org/learn/history.html [2] https://www.cl.cam.ac.uk/~mjcg/papers/HolHistory.pdf https://www.cl.cam.ac.uk/~mjcg/papers/HolHistory.pdf