5 ms·
> it's full of magic. You can feel it, but you can't really understand it without digging through the source code. Are you trolling? If not, care to provide co
by llambda 13y ago
> it's full of magic. You can feel it, but you can't really understand it without digging through the source code.
Are you trolling? If not, care to provide concrete examples?
I've written a number of small applications in Clojure and I find that it /lacks/ magic, even in comparison to something like Python (which is generally highly un-magical). For instance, Clojure's namespaces prevent circular dependencies; while a simple example, this is idiomatic to the larger philosophy of Clojure and indicative of a general dislike of magic that permeates the language as a whole, in my experience.
- leishulang 13y agoLisper trend to write one-liners with functions such as map, doseq etc. with big combination chains with many other functions. When doing this in a dynamic type language with no documentation, I guess that's why he calls it magic.
- s_kilk 13y agoHow in hell does 'map' qualify as a magical function? Though I suppose that for a programmer who couldn't understand a simple concept like map, damn near anything would look like sorcery to them. ( to clarify, I'm not accusing you of being unintelligent , just wondering-out-loud )
- obviouslygreen 13y agoAs a Clojure noob I can see 'map' and quite a few other functional things seeming seeming like magic to programmers who aren't used to the paradigm. Until you get used to thinking that way and using the tools, they seem a lot less intuitive.
- fogus 13y agoI can't speak a speck of German. The words look so long and intimidating and I find that if I try to pronounce them I get lost from the beginning to the end. The worst part is that sometimes German words look like something in English and when I try to use them in sentences my German speaking friends giggle at me. German definitely seems less intuitive as a spoken human language.
- agentultra 13y agoThere is very little that is 'magical' about a lisp-like language (in terms of the bastardized vision of 'magic' popularized by blessed hashes, operator overloading, and dynamically constructed objects in various scripting languages). There are few concepts required to understand it: (function arg arg) ; is the default form And every form is passed to eval, which calls apply, which calls eval... until you get to a fully expanded form and the final call to eval. (map #'my-func '(1 2 3 4)) ; might eval to (lambda () (my-func 1) (my-func 2) ...) ; which when passed to apply might result in (list 1 4 9 16) ; which eval's to itself, a list object... 'list being a primitive I just describe a theoretical evaluator (#'map is probably not implemented this way in most lisps). You can implement eval/apply in terms of a register machine if that makes you happy. Just read SICP for a good, basic description of one. I appreciate what the Algol-derivative languages have done and what they're useful for; but there are a large class of programming problems where telling the compiler how to solve your problem for you is far more efficient than manipulating the machine with primitives. It all boils down to that eventually and lisp-like languages simply take you to higher levels of abstractions with consistent semantics.
- dkarl 13y agoI think magic is not the right word here (and I see that you do not endorse it yourself, merely attributing it to him, a distinction others are ignoring.) Instead of magic, I would call it bad or unfamiliar style caused by a habit of doing everything in a single expression with large unnamed sub-expressions. This is much easier to do in functional languages because of how well functional idioms compose with each other. Martin Odersky gave an example of this in Scala in his style talk at Scaladays. Sometimes it seems simplest to express things in one expression: jp.getRawClasspath.filter( _.getEntryKind == IClasspathEntry.CPE_SOURCE). iterator.flatMap(entry => flatten(ResourcesPlugin.getWorkspace. getRoot.findMember(entry.getPath))) But giving informative names to the subexpressions can make things clearer for the next programmer to come along: val sources = jp.getRawClasspath.filter( _.getEntryKind == IClasspathEntry.CPE_SOURCE) def workspaceRoot = ResourcesPlugin.getWorkspace.getRoot def filesOfEntry(entry: Set[File]) = flatten(workspaceRoot.findMember(entry.getPath) sources.iterator flatMap filesOfEntry When to use named vals instead of subexpressions is a matter of style and judgment. From my limited and dated experience, the "one big expression" style is more common and more culturally accepted in Common Lisp than in other languages I've used. You could even call it the norm. In less expressive imperative OO languages, programmers are used to using a plethora of named variables, simply because they usually can't avoid it. In languages like Scala and Clojure, there's bound to be some culture clash when people who are used to more or fewer explicit names have to read each others' code.
- tomp 13y agoI understand map. Here's the code I was trying to understand. https://github.com/nakkaya/net-eval/blob/master/src/net_eval/core.clj#L16 https://github.com/nakkaya/net-eval/blob/master/src/net_eval... I'm not sure I do even now. I mean, I kinda know what different symbols and functions do, but I couldn't write it myself.
- nickik 13y agoWhen you say full, of magic I think you mean the core langauge, witch is actually very simple. The example you provide is from a small test lib somewhere one github. Lets look at the macro, once you understand the basic macro concepts, witch are actually quite simple but still hard to understand. Its like a normal function, exept that the function code will be added to the var as data.
- llambda 13y agoIt's a (fairly simple) macro that defines a function which while doing so associates a quoted function definition (the same as the function being defined) with the metadata of the defined function's var: it might require a double reading (based on my inferior description) because it's got some meta-ness going on. But the salient point here is there's really nothing magical about what's happening there.
- andrewvc 13y agoIf you understand clojure that code sample isn't hard to understand. Of course, I don't really know what it does, because reading 4 lines in a library without knowing anything else is always confusing.
- Anderkent 13y agoIt puts the code of a function into its metadata so that it can send it for remote evaluation easily (see fire-request below that extracts the :task metadata and sends it to a remote nrepl server).
- fogus 13y agoI'm confused. Is it magical because you don't understand it, or do you not understand it because it's magical? It seems like you're saying the first one.