> As a side note, expressing configurations in Clojure S-expressions makes a ton of sense. Clojure S-expressions provide a superset of JSON and Clojure's eval allows you to define a function to compute certain values. It's an escape hatch so that you're configuration files don't need to become accidentally Turing complete. The Turing complete nature of your configuration files is well defined as Clojure.
I had posted a while back wondering why more formats do not just derive from sexp or SXML (yes, say that out loud in the office). As I think some Lispers (I am even below beginner) cannot help but notice that if sexpr are coincidentally (I am sure it can be done without, but still, I am not sure if McCarthy and company just started with sexp or choose it specifically and held their ground beyond it was their choice) core to the lisp's homoiconic power-features, why more people do not just want sexp as the core data definiton, keep the data and program as close as possible, and just macro the data back, tossing back and forth between code and data as the division is limited.
Anyway, I like that far more intelligent people than me not only like this idea, but are encouraging it and pushing it forward.
(Yes, flame away. I know some people love Lisp and hate, I just thought it is an interesting premise; I am ready for you to throw shoes at me, HN.)
The whole nasty "configuration" problem becomes incredibly more convenient in the Lisp world. No more stanza files, apache-config, .properties files, XML configuration files, Makefiles — all those lame, crappy, half-language creatures that you wish were executable, or at least loaded directly into your program without specialized processing. I know, I know — everyone raves about the power of separating your code and your data. That's because they're using languages that simply can't do a good job of representing data as code. But it's what you really want, or all the creepy half-languages wouldn't all evolve towards being Turing-complete, would they? https://sites.google.com/site/steveyegge2/the-emacs-problem
Spec - https://github.com/edn-format/edn
Walkthrough - http://www.compoundtheory.com/clojure-edn-walkthrough/
Thanks for reminding my to finished the EDN docs.
You can close your P tags or not; if you don't, the next opeining one is a new paragraph, with the previous one assumed closed. Similarly with LI tags in lists or the multiple levels of stuff in TABLE.
That makes HTML "code" marginally easier (at least in terms of effort) for humans to write and maybe also read, and for programs to error-check and correct. It's also led to waves of shitty HTML code and generations of smarter programs to guess the intentions of stupid HTML generators.
XML, being more strictly defined, could have followed the lead of Lisp and done without the closing tags. I guess people felt the need for a security blanket of closing-checkable tags, or its slightly better human-readability.
HTML (well, SGML, in this case) was designed for humans hand-authoring large documents. If your opening tag is a few hundreds lines above the closing tag, a little redundancy is handy.
Remember, HTML is a markup format, not a data format. Tags were designed to add a bit of data to what is otherwise a plaintext document intended for human consumption.
Project Jigsaw which will be a big part of Java 9 aims to make the JVM more modular which will reduce the memory footprint substantially. Personally I would like to see a version of Clojure that targets this JVM specifically and abandons backwards compatibility.
Leaving the JVM means you abandon the decade of libraries many of which you simply can't get on any other platform (in particular for the enterprise). Given that Clojure has been gaining a lot of ground in these large companies it seems like a missed opportunity.
> time for x in $(seq 1 100); do ./helloworld.py ; done
real 0m1.240s
user 0m0.902s
sys 0m0.343s
That's reasonably fast.Java for comparison:
> time for x in $(seq 1 100); do java Hw; done
real 0m4.952s
user 0m4.051s
sys 0m1.071s
And I had to compile java first. Still, I expected worse from java TBH.But for example one of the areas that Clojure has been doing well in is the enterprise big data space which is dominated by the JVM based Hadoop ecosystem. Likewise many companies feel comfortable bringing in Clojure because they can leverage their existing Java libraries.
My point was that getting rid of the JVM loses a lot of what made Clojure actually successful.
> Although parts of the language may be very close to Clojure (they are both lisps after all), language parity is not a design goal. We will take the features from Clojure or other languages that are suitable to our needs, and feel free to reject those that aren't. Therefore this should not be considered a "Clojure Dialect", but instead a "Clojure inspired lisp".
And I agree that seeing maybe Clojure 2.0 abandon backwards compatibility with Java < 9 would be nice.
Pixie is not officially connected to Clojure in any way.
The creator has been involved in Clojure's development, and is remixing parts he likes into a new language and platform. I would peg this more as a research project that the Clojure team could take some pointers from.
Blame Clojure not the JVM.
https://nicholaskariniemi.github.io/2014/02/11/jvm-slow-star...
Besides if 0.04s is still too slow, there are quite a few (commercial) AOT compilers to native code available.
However, Pixie does look quite cool.
What I am missing in Clojure is the ability to take advantage of type metadata to compile it AOT to Android Dalvik/ART friendly bytecode.
Apparently not even 1.7.0 will fix the performance issues.
By comparison, on the same machine using an equivalent program
- Lua 5.2.3 takes 20ms
- CPython 2.7.5 takes 40~45ms
- MRI 2.0.0p481 and CPython 3.4.3 clock in at 55~60ms
- Pypy 2.5.0 takes 85~95ms
> Some form of package distribution support... could this be piggy-backed on Clojars?
There is Dust :
https://github.com/pixie-lang/dust
which pulls packages from Github.
Clojure:
(defn blub-extra [a b]
(blub (inc a) (inc b)))
8 parens + 2 bracketsScala:
def blubExtra(a: Int, b: Int): Int {
blub(inc(a), inc(b))
}
8 parens + 2 bracesJava:
Integer blubExtra(Integer a, Integer b) {
return blub(inc(a), inc(b));
}
8 parens + 2 bracesRuby:
def blubExtra(a, b)
blub(inc(a), inc(b))
end
8 parensPython:
def blubExtra(a, b):
return blub(inc(a), inc(b))
8 parens, one colonC:
int blubExtra(int a, int b) {
return blub(inc(a), inc(b));
}
8 parens + 2 bracesIt's roughly the same numbers of brackets (or equivalent) in Clojure, Scala, C and Java. A bit less in Python and Ruby.
def blubExtra(a: Int, b: Int): Int = blub(inc(a), inc(b))
The original would need an equals thrown in there, otherwise it's procedural syntax (IIRC, has been deprecated or will be in the next release) which has a return type of Unit, thus not compiling when specifying a return type of Int. def blubExtra(a: Int, b: Int): Int = {
blub(inc(a), inc(b))
}F#:
let blubExtra a b = blub (inc a) (inc b)
4 parens.
S-expressions are uniform in that they all look the same way. This means you have one form for literally everything in the program and you will have no problem parsing that form. It makes reading, mentally parsing and editing easier because everything is neatly delimited by parentheses.
In terms of readability, do you have any particular difficulties parsing the following code?
(define (sum/recursive lst [sum 0])
(if (null? lst)
sum
(sum/recursive (rest lst)
(+ sum (first lst)))))
We are defining a function, sum/recursive, that will take a list and return the sum of all the numbers in that list.We use a default value of 0 for a function parameter called sum to store the sum. When the input list is empty ('(null? lst)' returns true) we return that variable. There is no return keyword, we just specify that variable and it will be returned.
If the list isn't empty, we apply sum/recursive on the rest of the list and as a second parameter we add the first number in the list to the already accumulated sum ('(+ sum (first lst))'). Using matching parens in your editor will make it obvious when you have matched the right amount of parens.
It should be noted that Racket, this Lisp variant, uses '[]' as well to delimit certain parts, for readability.
In any case, the bigger part of the being productive in a codebase is to figure out how it encodes the domain, what idioms and patterns are favoured etc. So sometimes, it's just not worth adding another source of aggravation for "new arrivals".
If you treat the language as a user interface to your computer, shouldn't things that do different things have different appearances, to help you distinguish them at a glance?
In most ways I care about, Clojure is actually safer than C#. Now, if you're coming from an ML HM language, sure, you'll be taking a step back perhaps.
Lisp languages in fact have the same(ish) amount of parentheses as any other language, the trick is that the placement slightly differ: the opening parentheses come before the function name, rather than after it. Ie foo(bar) => (foo bar) . foo(bar(baz)) => (foo (bar baz)).
(20 . > . (10 . / . 5))
may be more clear than (> 20 (/ 10 5)) [1] http://docs.racket-lang.org/ts-guide/
[2] http://docs.racket-lang.org/guide/contracts.html?q=contractsWith Clojure/Lisp languages you are basically starting from the beginning. Most of the approaches you would take to constructing your applications don't work. It just takes a lot of practice for you to recognise patterns and then both the typing and parentheses will seem natural.
(Can't help you on the brackets. I mostly stick to Scala myself)