Return Styles: Pseud0ch, Terminal, Valhalla, NES, Geocities, Blue Moon. Entire thread

LITHP

Name: Anonymous 2015-08-07 18:15

Some of this criticism is related to Common Lisp and was fixed in Scheme or Racket. So it is mostly about why you should prefer Racket to Common Lisp or Clojure.

CONS-pairs simplicity is deceiving: CONS introduces mutability, together with silly notions of proper and improper lists, while impeding advanced and optimized list representations, so you can't have lists with O(log2(N)) random access, catenation and insertion, like Haskell's finger trees.
NIL punning (treatment of NIL of as empty list, false and void) breaks strong-typing and goes against lambda calculus, which hints us that IF should accept only TRUE and FALSE, which should be functions (Church Booleans), so all objects must be explicitly coerced to boolean for use with IF. Common Lisp has a confusing lot of NIL/CONS related predicates: there is CONSP, LISTP, ATOM, ENDP and NULL, while TYPECASE discerns between CONS, LIST, ATOM, BOOLEAN and NULL. The ATOM predicate considers NIL an atom, so if you have some code that should be invoked on every list, you can miss some empty lists. Hash-table access returns NIL, when key isn't present, making it harder to store empty lists. Some Lisps demonstrate half-broken behavior: for example, Clojure, discerning between nil and empty-list, still allows using nil in-place of empty-list; moreover, Clojure introduces true and false, duplicating nil and confusing semantics even further. NIL punning is the single worst Lisp wart, reminiscent of PHP and JavaScript horrors.
Non-Lispy behavior: FORMAT function competes with regular expressions in providing cryptic and unreadable DSL, indulging obfuscated code like "~{~#[~;~a~;~a and ~a~:;~@{~a~#[~;, and ~:;, ~]~}~]~:}", which could have been easily replaced with SEXP based format. On the other hand, Lisp misses string construction, like "Name=$name, Age=$age", so you have to carry FORMAT everywhere. LOOP macro employs baroque Pascal-like syntax with a lot of clauses, having complex interplay with each other, which would confuse newbies and annoy Lispers, who love simpler solutions, playing nicely with lambda calculus, like letrec.
Over-engineered OOP: despite Lambda Calculus prescribing using lambdas to construct objects, most Lisps implement full blown class-based OOP, like CLOS, conflicting with Lisp's minimalism and complicating semantics. Moreover, lists/conses and booleans don't have first class citizen rights in these ad-hoc object systems, meaning you can't overload CAR or CDR, so you can't implement your own lists, like, for example, a list-like interface to filesystem, where a directory could behave as a list of files and every file as a list of bytes. CLOS generics (multi-methods) clutter global scope and collide with functions. Package symbols have dynamic scope, which is argumentably bad and shouldn't be indulged, while packages are global and first-class, so you can't easily get a sandboxed environment (like Unix's chroot) by making a package with only safe functions. Instead of providing viable encapsulation, some Lisps treat the symptoms by introducing second namespace for variables, so that identifiers would have less chances to collide. Other Lisps, like Clojure, disapprove OOP, using some ad-hoc package systems and kludges, like "protocols".
Duplication is not the right thing: CONS duplicate arrays and lists; QUOTE duplicates QUASIQUOTE, which for some reason implemented as reader macro, so you can't overload it for you own use; LOOP duplicates DO; symbols duplicate strings; chars duplicate single-letter symbols. Package encapsulation duplicates OOP, which in turn duplicates encapsulation features provided by lexical scope. Growing from broken OOP encapsulation, there is an explosion of comparison functions, just to compare for equality we have: =, char=, string=, eq, eql, equal, equalp, tree-equal, string-equal, char-equal; worser, eq compares pointers and has undefined behavior, so it should be part FFI, instead of being exposed with normal interface. Analogously, AREF, SVREF, ELT, NTH, CHAR, SCHAR, BIT, SBIT - all do exactly the same.
Verbosity and inconsitent naming: define and lambda are most used keyword, yet take 6 character each; then we have monstrosities like destructuring-bind and remove-if-not, which could be named just bind and keep. Verbosities like MAKE-HASH-TABLE, MAKE-ARRAY and (DECLARE (INTEGER X)) ensure that you will avoid optimized structures and type-checking at all cost, making your code slower. In rare cases, when names ain't verbose, they are just cryptic, like PSETF, CDAADR and REPLACA. Macros LET and COND have especially bloated syntax: where simpler (let name value …) would have been enough, LET adds additional 2 levels of parentheses (let ((name value)) …) just to annoy you. CLOS and defstruct syntaxes are especially verbose, which is aggravated by absence of self/this context. Many people complain about absence of infix expressions, which could have been easily supported through reader macro, like {a*b+c}, and while Scheme does support infix expressions, it misses operator precedence, making it incompatible with formulas you may copy-paste from your math textbook. LISP lefts unused a lot of special characters, which otherwise would made code succinct and provided visual cues: for example, you have to write (list 1 2 3), instead of [1 2 3]. Coercion naming scheme impede composition: (y->z (x->y ...)) hides the y entrepot, while (z<-y (y<-x ...)) would have underlined it.
Missing features: While Lisp does support complex and rational numbers, it doesn't support vector arithmetic, so you have to write something like (map 'vector (vector x1 y1 z1) (vector x2 y2 z2)), making geometry and physics code exceedingly verbose. A few important functions, like SPLIT and JOIN, are missing from standard library, which for some reason includes rarely used string-trim and string-right-trim, although JOIN usually simulated with (format nil "~{~a~^-~}" '("a" "b" "c")), making code impenetrably cryptic. Absence of good type system, call-by-name (lazy evaluation) and immutability, which really makes functional programming shine. Although, Qi does provide acceptable type system and Clojure introduces immutability, we can't have all this in a single production quality Lisp. Call-by-name is more of an on-demand-feature to be used in some contexts (like implementing if/then/else special-form), but no Lisp features it, despite call-by-name being natural semantics of Lambda Calculus. Some popular Lisps, like Clojure and Common Lisp, don't even guarantee TCO (tail call optimization), meaning that expressing advanced control structures would be hard. No Lisp, beside Scheme, supports continuations - silver bullet control-flow feature, although some Lisps do support goto - limited form of continuations. "It needs to be said very firmly that LISP is not a functional language at all. My suspicion is that the success of Lisp set back the development of a properly functional style of programming by at least ten years." -- David Turner.
Horrible community: Lispers are unhelpful, inert and elitist, so much that they continuously fail to coordinate the development of Lisp. The backwardness of Lispers shows even in their choice of long obsolete GNU/Emacs (an orthodox command line text editor without mouse support or any GUI at all) as the only true IDE and tool for everything. Lispers are the ones who will make fun of newbies, instead of helping them. Lispers will call you "retard", if you don't know the meaning of buzzwords like "pandoric eval", "CPS" or "reversible computation".

Name: Anonymous 2015-08-08 11:29

Object & semantic equality are some of the more difficult problems to handle in language. Having a ton of explicitly different equality comparisons is much cleaner and easier in the long run.

Newer Posts
Don't change these.
Name: Email:
Entire Thread Thread List