Hacker News new | past | comments | ask | show | jobs | submit login
Pixie: A sweet Clojure-ish language (goodstuff.im)
140 points by coding4all on March 9, 2015 | hide | past | favorite | 105 comments



I like the side-note.

> 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.)


Steve Yegge wrote a blog post about this a few years back that I found eye-opening.

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


Great quote. This idea is still not too popular, unfortunately. There are a lot of folks out there that get real mad when configuration is code. Notably, sysadmins that feel forced to learn Clojure or <insert-language-here> to configure an application. "Why not XML or JSON?", they say.


Most well-designed applications will separate the administrative interface (configuration) from a programming interface (the API), even if the same langauge is used for each one. If you do this properly, most administrators are not going to care what language your configuration is in so long as it's clear and consistent.

In my experience, the main annoyance using programming languages for configuration is the need to use explicit string literals for every string in your file. List separators are another major source of clutter in configuration files, though this is theoretically not a problem in clojure. The second problem is the tendency to be undisciplined and allow too much program logic in configuration files resulting in complex and unclear relationships between options and behavior.

Personally I do all my configuration in yaml now. Even if I was using lisp I would use yaml whenever possible for configuration and static resource definitions, because yaml is very portable.


It really depends on the environment and culture. In Python web apps for example it's very popular to keep project configuration in Python dicts and lists, which are just Python code (as opposed to using something like YAML or JSON for config).


Popular, but an anti-pattern. People start including production configuration as a module inside the build.

The Right Way (TM) is loading from env vars.


By "inside the build" do you mean in the git repo?

Because there isn't really a such thing as a "build" for a Python web app, it's a dynamic language. It's not like Java where you'd have to recompile the whole app if you packaged your config inside the compiled jar.

In Django apps, there's an env var called DJANGO_SETTINGS_MODULE that points to one of multiple settings.py files, and you change that var depending on which environment you're working in. Then typically you also would want to store individual variables that need to be secure (stuff like any secret keys and database credentials) in env vars, but the overall structure of your config is just a python dict in settings.py.

For reasons that Yegge touches on in the blog post I linked above, you really want a tree structure for configuration of any complexity, and env vars don't provide that.


I think he means that the configuration file is on the library path is read using an import statement rather than parsed explicitly from a standard path like etc/.


Well, technically, JSON is just a Plain Old Javascript Object, with restrictions (no expressions, quoted keys).


Sort of, at least in the sense that you can eval JSON from JS code rather than having to parse it yourself. This is one of many language concepts that JavaScript cribbed from the Lisp/Scheme family of functional languages.


Once you use Clojure's EDN, you start to cringe when you see JSON.

Spec - https://github.com/edn-format/edn

Walkthrough - http://www.compoundtheory.com/clojure-edn-walkthrough/


I was excited to hear someone's Guile Scheme answere to Sinatra, Artanis (yes, I know, cute), led me to the Summer of Lisp winner list, including this of course and the Learn You a Datalog guy. Naturally, that led me to EDN.

Thanks for reminding my to finished the EDN docs.

http://www.learndatalogtoday.org/


Tell me about it. First thing I asked when I saw HTML over a decade ago was "Oh so you can close tags out of order?" - "Uhm, no, the last opened tag must be closed first" - "Then why do I need to say its name when closing? There's no ambiguity, it's always 'close the last opened tag', so why say its name again?". Folks at W3C must not know Lisp.


I'm happy to disclaim that I have nothing to do with the mess that is the HTML standard! But if I had to guess I would say that the ending tags in HTML add a modicum of redundancy that allows for some of the crazy/creepy/smart error correction browsers have been doing for decades:

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.


> That makes HTML "code" marginally easier [...] and for programs to error-check and correct.

This is a great point. It's not subjective and I'm pretty sure it's right. I hadn't thought of that. I guess there is a use for redundancy sometimes. If the point is to make the language welcoming to beginners then this decision makes sense.

I wonder, though, if they made the same mistake that the SQL people did, in devising a language with characteristics that are advantageous to some imagined target group ("non-programmers") but that ends up getting used just by programmers who then hate the training wheels.


> "Then why do I need to say its name when closing? There's no ambiguity, it's always 'close the last opened tag', so why say its name again?". Folks at W3C must not know Lisp.

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.


We already have a solution for that:

  if whatever
    ...
  end # whatever


  (p
    ...(bunch of stuff inside p)...
  ) ; p
Now it's optional, not part of the standard, and the language is cleaner for it, while allowing for a way to help your described scenario.

Folks at W3C want to fix all kinds of non-existing problems (like HTML5 canvas when there's already OpenGL viewports).


This seems like bit of a short sighted move not that I disagree with it.

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.


In fact JVM is pretty fast. If you run a simple java app without dependencies and only displaying "Hello world" it will run in about 1s on modern hardware. The problem with Clojure is AFAIR related to parsing and loading a big number of namespaces which is quite slow.


1s to print hello world is an awful lot I would like to point out.


Upvoted you because I agree. JVM has many strong points but I don't think anyone is disputing that startup time is a weakness. I've used some java tools that you invoke from a command line and I'm always slightly annoyed by how slow they are.

As an aside - I was trying to reduce -Xmx to improve HelloWorld startup (lol idk...) and Xmx smaller then 1024k and it couldn't start up with less then 1024k so there's that.

On my windows computer (also I barely know what I'm doing so probably even timing it wrong).

  [Mon Mar 09 03:22:31 zebra@ZEBRA:~ ]
  $ time a.exe
  Hello, world
  real    0m0.098s
  user    0m0.015s
  sys     0m0.015s
  [Mon Mar 09 03:22:34 zebra@ZEBRA:~ ]
  $ time java Hello
  Hello, world!

  real    0m0.285s
  user    0m0.000s
  sys     0m0.031s



Worry about -Xms rather than -Xmx for startup times.

I suspect there are ways to make it faster (e.g. there's a nashorn runner that starts up appreciably faster than "proper" java), but the main use case for java is server-side programs that run for days or weeks between restarts, so it's optimized for that use case.


the main use case for java is server-side programs that run for days or weeks between restarts, so it's optimized for that use case.

Unfortunately for the folks who still have to use Java desktop software written in Swing.


Sure it's a lot, but clojure startup times are significantly longer than that.


> If you run a simple java app without dependencies and only displaying "Hello world" it will run in about 1s on modern hardware.

> 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.


Out of curiosity which Java? OpenJDK or Oracle or IBM?


     > java -version
     java version "1.7.0_72"
     Java(TM) SE Runtime Environment (build 1.7.0_72-b14)
     Java HotSpot(TM) 64-Bit Server VM (build 24.72-b04, mixed mode)


Thanks. I would have figured hot spot to be better.


You mean 60-80ms. Not 1s. Try it.


It can call into C libraries so there is a whole other ecosystem available to it.


Which is nice. And it could definitely open up new avenues for them.

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.


Who got rid of the JVM? Pixie is not Clojure 2. Clojure still exists and you can use it, but now Pixie also exists and you can also use it. There is no downside unless you think developing languages which don't run on the JVM is a waste of time.


Yes, but Clojure can call the same C libraries, plus the JVM ones.


From the README

> 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.


> This seems like bit of a short sighted move ... Leaving the JVM means you abandon the decade of libraries

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.


Jigsaw keeps getting moved back, to the point that I don't have much faith it will be in version 9. Wait and see, I guess.


> And the JVM has the slowest startup time of any runtime I've ever encountered.

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.


.04 is user time. The elapsed time was .12 - this is how long you have to wait. Still it's a fair point: 120ms is noticeable but not painful.


Right, I looked into the wrong place.


It's unclear what machine and JVM configuration they're using. Using the JVM 1.8 (java version "1.8.0_20") on a 2010 MBP (2.4GHz i5) I get ~190ms (180~200) for their program.

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


You are missing clojure start time which for me is over 1.5 seconds on top of the jvm start time.


I'm not missing anything, I'm saying the statement

> And the JVM has the slowest startup time of any runtime I've ever encountered.

looks completely correct in and of itself. Clojure's startup time can be blamed for making things worse (by a fairly significant bit), but the JVM is already, without Clojure, the slowest-starting runtime I have on my machine. And that's what pjmlp objected to.


I get 130ms on Windows 8.1, Core Duo 2.53 GHz with jdk1.8.0_40. And 120ms If I disable the JIT.

With a normal hard disk.

Maybe it does take a few ms more than Lua or Python, but hardly anything significant.


> Maybe it does take a few ms more than Lua or Python

Yeah, like 3 to 6 times longer.

> but hardly anything significant.

Well if 6x is not significant, surely Clojure's second start time is hardly significant.


I don't want to install Lua or Python just to test how long an Hello World takes, hence my "maybe".

Even if I am wrong, 6x here means 130ms, whereas Clojure time is in the order of seconds.

Big enough to warrant a few entries on their roadmap.

http://dev.clojure.org/display/design/%27Lean%27+Runtime

http://nicholaskariniemi.github.io/2014/02/25/clojure-bootst...


> There are some things that I would like to see from/in Pixie...

> 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.


I'm already replacing my project's ancient Go and Rust based services with Pixie powered end points!


Could you elaborate some points that motivated you to switch from go? What would be next?


This week's hottest language is SVIRFNEBLIN. It's got everything: privilege escalators, compile-to-malgeboge, mini-hdmi, and that thing where your types are all fragments of Sapphic erotic literature!


Oh, Stefon, don’t ever change.


Language and implementation both look very promising! I was looking for small footprint and fast startup modern lisp for a long time for my embed hobby projects. And finally it's here! I'm really excited about this language and where it stands now compared to when I first discovered it.


You should check out Scheme implementations like Guile and Chicken.


I want to see a clojure clone embedded as a Go scripting language. The immutability means that the interpreter would be mostly threadsafe, and thus would support goroutines well.


Embedding an immutable language in a mutable one is a recipe for awkwardness - how would you expose host-language things to the inner language? Better to do it the other way around - mutable scripting language embedded inside immutable host.


Clojure is an immutable language built on top of mutable hosts. Interop is handled beautifully. A go hosted Clojure (gojure?) would probably be fine.


Calling Clojure from Java is not remotely what I would call beautiful; it's a lot of Strings and pain (especially when you compare to calling Scala from Java). Calling Java from Clojure is substantially more elegant (it requires a structured FFI but Clojure is good at those).


I don't know if it would be an exact clojure clone, would need a few tweaks and the addition of native channels.


Well the closest I've found is https://github.com/zhemao/glisp which is similar syntactically, but doesn't have immutability.


otto + clojurescript would probably work, but would lack many features + thread safety.


Direct link to pixie's github https://github.com/pixie-lang/pixie


Can anyone verify if Pixie has concurrent multithreading or is it limited to greenthreads as described in the article? Based on the fact that atoms are implemented and they would not be necessary in a single threaded environment, I would guess that support for concurrent multithreading would be at least in the works, if not already possible.


A quick video if you want to see pixie startup time in action https://www.youtube.com/watch?v=LlDQTLRrcZI


Dynamic typing and parentheses are what keep me away from Clojure or Lisp like languages. How can I get over them?


There aren't many languages that have radically fewer parentheses than Clojure / LISP.

Clojure:

    (defn blub-extra [a b]
        (blub (inc a) (inc b))) 
8 parens + 2 brackets

Scala:

    def blubExtra(a: Int, b: Int): Int {
       blub(inc(a), inc(b))
    }
8 parens + 2 braces

Java:

    Integer blubExtra(Integer a, Integer b) {
        return blub(inc(a), inc(b));
    }
8 parens + 2 braces

Ruby:

    def blubExtra(a, b)
        blub(inc(a), inc(b))
    end
8 parens

Python:

    def blubExtra(a, b):
        return blub(inc(a), inc(b))
8 parens, one colon

C:

    int blubExtra(int a, int b) {
        return blub(inc(a), inc(b));
    }
8 parens + 2 braces

It's roughly the same numbers of brackets (or equivalent) in Clojure, Scala, C and Java. A bit less in Python and Ruby.


Scala example is wrong, wouldn't even compile; should be:

    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))
    }


Thanks for the typo spot. I've not written Scala for about 5 years. Unfortunately I can't go back and edit my post.


You can do it in Ruby with 4 parens, or even 0 if inc is really just +1. I wouldn't ever write it with so few but if we're really going down this rabbit hole then we ahould get it right.


Please feel free to contribute a Ruby example (as long as it's normal and idiomatic, this isn't a competition)! I've not written Ruby for years.

(inc was just a random function for the sake of showing invocation so it's not really fair to use operators)


I think it's the positioning of them that makes them stand out to people, plus the fact that they tend to bunch up at the end of things.


Of course, I know. But most people express it as 'too many parens', without (I believe) actually thinking too hard. I was just trying to provoke a few thoughts!

The position of parens is something to get used to, but then again so is Python's indentation, Scala's type system, etc etc. Every language has something unique to get used to.


as someone already pointed out on twitter:

F#:

let blubExtra a b = blub (inc a) (inc b)

4 parens.


Usually we would write it as:

let blubExtra a b = inc b |> blub (inc a)

which 2 parens less, but at the cost of using the (very idiomatic) pipe operator.


If you truly have been shunning Lisps because of parentheses I can only tell you that it will start to make sense once you see that they're just lists and that the fact that everything (including your code) is some variation of a list means that you are now (sometimes in the background) able to modify everything as if it was a list.

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.


Lisp's super power (homoiconicity) comes at a trade-off of reduced discriminability. A good syntax highlighter and well-indented code (like you provided) reverses this effect considerably, but imho, it still takes a lot of getting used to for beginners.

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".


I disagree with regard to Clojure. IME, the fact that it's a lisp doesn't seem as hard for noobs to grasp as immutability by default, or pickup up the functional programming mindset. We usually go for folks who use Emacs, so they may already have an indoctrination.

When you compare Clojure to other lisps, I think you'd agree it's more discriminable, given the plethora of literals that dont use parenthesis: vectors [1 2 3] sets #{1 2 3} maps {:key "value" :name "Bryan"}


I've used clojure for some weekend hacking and have found that the biggest challenge is feeling like my code is non-optimal. I can get stuff to work and could build real stuff in clojure, but I hesitate because I feel that it's not necessarily idiomatic.

I guess I need a clojure mentor for the first non-trivial project. There really isn't that much idiomatic web-related code out there to read, and with clojure there is also quite a lot of variation in how systems get designed (b/c of the power and expressiveness available).

This is not an excuse, just noting the factor that has turned out to slow me down. If i had more leisure time I'd just power through and build stuff until I arrived (through trial and error) at my own sense of best-practices / design tradeoffs. That has yet to happen but will someday.


> S-expressions are uniform in that they all look the same way.

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?


The braces become "invisible" after some training. Different elements of the program are distingishable. "+" is different from "if", which is different from "42".


It's all about people, so there are likely not cut and dried answers, but I know I have always found C style code a bit easier to read than Lisp style code. Part of this may be due to other conventions, such as larger indents in C code.

Like you say, with training, the differences are probably not that big a deal, but I don't think they are something to completely ignore, either.


the point is to free yourself to focus on semantics rather than endlessly learning syntax


Could you clarify? In what language(s) is the learning of syntax "endless"?


I think Clojure is actually a lot safer by default than most people expect for a Lisp. Check out this comparison I wrote up between C#(or Java), F#, Clojure, and JavaScript on common edge case safety. http://deliberate-software.com/programming-language-safety-a...

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.


Clojure is horribly unsafe. I spent a year writing Clojure and half the time we were fixing bugs where someone had wrapped a map in another map or changed the shape of a data structure. For all that's worth, I'd rather use Javascript. To add insult to injury (the amount of wasted time on something that could be easily checked by a compiler and a sane type system) there's all the bad habits you acquire and the general lack of confidence in your code, which took a good six months after that to cure. I'm sticking with types now, thank you very much...


Sounds like you needed Schema, which can ensure the shape and contents of a map as :pre and :post assertions in every function you annotate, then be turned off for production use. https://github.com/Prismatic/schema

That's why I come back to Clojure every time, if I need anything, it's available as a library. Need better typesafety? Just add in what you need with a macro or two. (Schema is not much more than that).

That's not really possible easily with Javascript, and Javascript has a lot more unsafe by default edge cases than Clojure. I'm not sure why if a mostly safe dynamic language bothers you, you'd now prefer an extremely unsafe dynamic language?

Lastly, types only give you a single dimension of safety, is this that exact shape, and ensuring I don't put a square peg into a round hole: both of which Schema adds in easily. Clojure is ALSO safe along many other dimensions, like thread saftey, immutably, null reference exceptions, etc.


80% of the problems I had to deal with (in a live, real-life Clojure system that had to be maintained and supported, not a hobby-happy-slappy-project-thing) were caused by putting square pegs in a round hole. You're telling me I need to get a macro-based library and add :pre and :post conditions that check the structure of a map, as opposed to using a language with types?! Really??? Oh, and guess what, I am sure there is a Javascript library that does that too...


I agree with most of what you said, but

> Lastly, types only give you a single dimension of safety.

Dependent types can express a huge number of things, and are often limited only by your ability to describe what exactly you want.


Absolutely right, I was just comparing with the dominant Java or Python.

Dependent typing is some cool stuff, I'd love to see more of it.


I have been following Idris, quite cool.


Do you use a dependently typed language in production?


I don't really use anything in production, I am just a learner right now :)

There are some people using some of extensions for Haskell inspired by "dependently typed" systems in production.

Dependent typing is an active research topic right now, and I doubt any fully fledged dependently typed language is used "in production".

However, I was just pointing out that it is possible for types to express a wide variety of things that we do not normally associate with them. Even without full dependent typing, Haskell types are wonderfully expressive and powerful.


Oh, god, thanks for reminding me about the whole agent/atom/ref hell - another reason I'd rather erase the whole Clojure experience from my brain altogether...


Jesus, maybe you were not able to read a clojure book befor you started. Its amazingly simple to explain how to write thread safe code with clojure, and pretty easy to add concurrency safly.

There are 3 concepts that are all diffrent, and a couple yours ago core.async was added. All in all thats a amazingly simple and powerful combination. Everybody I have heard is pretty happy with these tools. What is your problem?


Agree to disagree. I do not enjoy the impossible to prove defensive coding around threads and callbacks. The core.async library made threading in Clojure for me to now be simple and pleasant compared to difficult to test mutexes and deadlocks.


You're the first person I've seen that is vocal about having a truly bad experience with Clojure. Even from other people who prefer strongly typed language, I've mostly seen them expressing it as "not their taste", rather than actively dislike it. Do you mind sharing your experience and what was wrong with Clojure? You put js as an alternative, but in term of typing, js is borderline one of the worse type system out there.


Not as an alternative, but as similarly unsafe. It's funny to see how all the Clojure advocates bash Javascript...


I don't know where this trick come from, but I've read it a long time ago, and you might find it helpful.

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)).


This trick is very helpful, but I would argue that there are still a lot more parentheses due to almost everything being written as a function in lisp. When I started programming in Racket arithmetic and comparison expressions tripped me up frequently. My tip to beginners in this area would be to use the dot-notation first, then switch to the standard way once comfortable. for example:

    (20 . > . (10 . / . 5))
may be more clear than

    (> 20 (/ 10 5))


parentheses, at least in my exp, just fade away after a while.. there's core.typed which is static typing for clojure [0]

[0] https://github.com/clojure/core.typed


Also Prismatic's schema. It achieves some of the same goals for why you would want strong typing:

https://github.com/Prismatic/schema


+1 for Prismatic Schema. It's not only an awesome way to validate your maps, but it is an extremely good way to write documentation.


It's also very worth looking at Typed Racket and Racket's contracts system!

    [1] http://docs.racket-lang.org/ts-guide/
    [2] http://docs.racket-lang.org/guide/contracts.html?q=contracts


Thank you for the link. I will look into the core.typed.


Time.

With 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.


Compile-time typing really is valuable, IME. Maybe you should look at Shen?

(Can't help you on the brackets. I mostly stick to Scala myself)




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: