Hacker News new | past | comments | ask | show | jobs | submit login
Wisp: a homoiconic JS dialect with Clojure syntax, s-expressions and macros (jeditoolkit.com)
113 points by spion on May 23, 2013 | hide | past | favorite | 49 comments



As somebody who contributes to ClojureScript, I genuinely do not understand the purpose of this project.

If you want a JavaScript with Lispy syntax, there are a few things like http://lispyscript.com/ -- Spiritually similar to CoffeeScript. But if you want Clojure semantics, there is ClojureScript: Very different than a simple transpiler like CoffeeScript. ClojureScript includes a standard library of rich data structures and utility functions.

But why would you want Clojure syntax without Clojure semantics? Especially since Clojure syntax implies several data types that JavaScript can't provide natively. It just doesn't make sense...


A primary benefit of things like Wisp is it makes it easier for non-clojure users to dive in and learn a clojurescript like language. I like JS and I like Lisps but the learning curve for clojurescript is too much if you don't know Clojure already. Wisp feels much more JS like; with my decent JS and decent Scheme knowledge I feel I could just dive in and play with it. Clojurescript does not leave me with the same impression, it feels like a lot of work to get up and learning.

Clojurescript's heavy dependence on the Clojure environment (JVM, leinigren etc) make it a real pain to get setup for. I have looked into clojurescript several times but thought "I better master clojure first". I have been getting a hang of Clojure slowly and plan to tackle learning clojurescript eventually but something like Wisp opens up the possibility of diving in without needing to be comfortable with all the Java crap.

I only tend to take up something when it takes me five minutes to start learning. I think most are the same way; it's the reason why Codecademy is so popular and why clojurescript's primary user base is Clojure users. The more users that can start learning a language in five minutes the better it is for that language. Clojure beat out other Lisp implementations primarily because it was easier to dive into for a greater number of humans than any other Lisp.

Wisp and other implementations like it make diving into Lisp->js languages much easier. It removes the large roadblock that is Java, a roadblock that is unnecessary if your target language is JS not Java.


Yeah, I think the concept of sticking a JVM in the middle of the process of generating browser scripts is very strange. Clojure has a lot of JVM specific quirks that don't make sense in the context of Javascript at all. And if you're coming from another Lisp/Scheme dialect, Clojure is definitely nontrivial to learn.

Wisp looks like Javascript was supposed to look before they bolted C syntax onto it. People say that Javascript is like Scheme with C syntax. So Wisp is like Javascript with Scheme syntax. I think this is something I would actually use.

I didn't know about LispyScript either, though. I would have to compare/contrast the two.


I like ClojureScript and use it a lot lately. Sometimes however it feels a little distant from JavaScript at times. This can be frustrating at times. Wisp is somewhere between ClojureScript and JavaScript.

Of course this means that some of Clojure's features (protocols and lazy sequences, atoms, etc.) are not available. On the other hand there are not so many opaque layers between your code and the target code.

Granted feature-wise it might be more similar to a scheme, but Clojure Syntax is so much more readable and I do not see a point why it would not be a valid approach.


> Of course this means that some of Clojure's features (protocols and lazy sequences, atoms, etc.) are not available. On the other hand there are not so many opaque layers between your code and the target code.

As a matter of fact I plan to provide protocols lazy sequences etc.. in form of (optional) libraries that can be included or omitted based on user use cases. I personally thing that most of these features are drawbacks when interacting with JS code, although I'd definitely used them in cases where interaction with JS is not a concern.


I've tried to elaborate my reasoning in the readme actually:

> Unlike clojurescript, wisp does not depends on JVM and is completely self-hosted. It compromises clojure's awesome data structures and embraces native JS data structures to be a better at cooperation with JS. Goal of wisp is to present a subset of clojure(script) language such that packages written in wisp can be consumed natively by wisp, clojure(script) and JS when compiled, without data marshalling or any code changes.

While I do like clojure(script) a lot I don't think it makes too hard to consume data structures from JS land and makes consuming data produced by clojure(script) awkward for consumption on the JS side. That is a the reasonable compromise for a great power, it's just I think I'd rather leverage JS data structures in immutable manner directly and provide more clojure like data structures in form of libraries. This would allow users to make best (or maybe worst) choices based on their constraints.

As of lispyscript it's nice project and as a matter of fact wisp is just a fork that never got merged in to upstream. I was convinced that clojure (or any other known lisp) syntax was better option than yet another new lisp. In addition I wanted full macros that unlike wisp lispyscript does not has. Also lispyscript has no lists, instead it uses arrays and I can continue this list over and over...

> But why would you want Clojure syntax without Clojure semantics? Especially since Clojure syntax implies several data types that JavaScript can't provide natively. It just doesn't make sense...

JS can do it otherwise clojurescript won't be possible, I just think these data types can be exposed via optional libraries as they have associated cost in terms of performance overhead and learning curve.

And to be quite honest I do hope that a lot of wisp parts will find it's way to clojurescript, it's just contributing to clojurescript turned out to be harder than bootstraping own version, since even pull requests for travis-ci integration tests require lot's of justification.


Also, I find the Google Closure library to be way too heavy for a transpiled language. It adds it's own library tools and separates itself from traditional JavaScript paradigms. Letting the transpiled language to do just that and doesn't impose it's own run-time restrictions would be perfect. After looking over Wisp real quick, it seems like it does just that.

I was pretty dissapointed with ClojureScript because it generates almost unreadable JavaScript; It includes an extremely heavy library that most people don't use and would never use; It depends on a lot of JVM specific things. For it to be a lot more successful as a compile-to-javascript platform it would need to move closer to native JavaScript than anything else.


I see some reasons on the guys site here: http://jeditoolkit.com/2012/09/16/coljurescript-feedback.htm...

Update:

Also, on the projects web site [0], it says that "Homoiconic syntax and macros are the primary motivations!"

[0] https://github.com/Gozala/wisp

I don't know how this project is in practice, but I think those goals are worthwhile. When it comes to Clojure proper, one of the many selling points is that it does Java better than Java. This project may be able to do the same for Javascript.


I agree. The comments here make me think that the commenters don't know all of the extra ideas that Clojure brings besides a "different syntax" to Lisp. Even just for the immutable, persistent data structures that support value semantics (& distinguishing state from identity), ClojureScript ought to go a long way to helping write better code.


Note that most functions exposed by wisp do not mutate existing data structures and match clojure in behavior, it's just they use array's instead of vectors and dictionaries instead of maps. My hope is that it will imply same immutable style even if underlying data types remain mutable.


Worse is better.

Wisp, I guess provides readable js as opposed to compiled js. That's a win.


Wonderful, one more language for me to consider in addition to Roy and Parenscript. I guess there's also Whalesong for Racket, but I don't know how clean the cross compilation to JS is. I've always been drawn to Clojure but the JVM kept me at bay. The fact that it's not "Lisp all the way down" also clouds my decision for it. I guess Wisp would be highly compatible with Lighttable?


Parenscript seems pretty cool. I tried Clojurescript about 2 months ago and the build process was disturbingly frustrating. :-/ I will take a swing at Parenscript next time I get on that particular project.


> build process was disturbingly frustrating

that pretty much sums up my experience with ClojureSctipt as well.


Same here, and also the use of Google Closure was pretty disappointing.


Can you clarify?


If you're interested in lisp without the JVM, there's always ClojureScript. Once the JVM compiler is up an running it compiles most of my ClojureScript code in about 1 sec, and there's utilities that auto re-compile code as files change.


"without the JVM" ... "Once the JVM compiler is up"

Does not compute! :P


Can't quite tell if you're serious or joking. In case it's the former: the ClojureScript compiler is implemented in Clojure, which runs on the JVM. The compiled code is Javascript, which doesn't require the JVM. There have been some discussions about making the compiler hostable from Javascript as well, but it's not possible just yet.


> but the JVM kept me at bay

> ClojureScript compiler is implemented in Clojure, which runs on the JVM


What is the benefit of having three ways to write strings?

        \a  ;; compiles to "a"
	:a  ;; compiles to "a"
	"a" ;; compiles to "a"
This is not meant as destructive criticism; I'm genuinely interested in the motivation for that.


To expand on others' answers: In Clojure, \a is a Java character, :a is a Clojure keyword, and "a" is a Java string.

    user=> (type \a)
    java.lang.Character
    user=> (type :a)
    clojure.lang.Keyword
    user=> (type "a")
    java.lang.String
The only unusual thing is the keyword. Fogus and Houser say this: "Because keywords are self-evaluating and provide fast equality checks, they're almost always used in the context of map keys." But here you're back to checking equality of strings. Not sure if the same is true for ClojureScript.

You can also use them as functions to look up values in maps. For example:

    user=> (:my-key {:other-key 1, :my-key 2})
    2
There are other places they're used--for example, list comprehensions with `for`:

    (for [x (range 10)
          y (range 10)
          :when (= x y)]
      [x y])
    => ([0 0] [1 1] [2 2] [3 3] [4 4] [5 5] [6 6] [7 7] [8 8] [9 9])
In Clojure keywords are nice to have.


Seems like a disadvantage to me. It's mostly just confusing and the only thing it affords is the ability to use :keywords as functions (:like so) which is just sugar for property access, so["like"]. This is broken, though.

The coolest thing about :keywords in Clojure is that they really are functions and you can do things like (map :keywords ontoSomething) to extract the same property out of many things. It don't work in Wisp.


What you're not realizing, though, is that each time you use the string "like" as a key for a map/dictionary, you're allocating a new object on the heap. So what if you have many keys, and they're all strings? What if you have many maps that share the same keys? That's a lot of memory to allocate, and strings are an extremely inefficient way to implement what is essentially a unique identifier to address map values. Instead, use an integer as a unique identifier.

That's basically what keywords do -- they are human-readable and compile down (prob. using some hash) into some integer, and the integer is stored globally only once. The biggest savings in memory comes when using maps, and that's how & why keywords get their name.


Javascript strings are immutable and literals are almost certainly preallocated and stored in a table of constants. Why should using a string keys cause heap allocations?


If you have a VM where strings are immutable and interned, you're right. Java doesn't guarantee that strings are interned (though you can ask the VM to intern it), so Clojure treats them differently.

Also, Java declared java.lang.String as final, so Strings can't be extended to implement clojure interfaces to get nice behavior, like IFn and IKeywordLookup.


The coolest thing about :keywords in Clojure ... don't work in Wisp.

Ok. That sucks. So pretty much anyone already a bit serious about Clojure wont be enticed by this then.

Edit: From the page:

    ;;    Keywords can be invoked as functions, that desugars to plain
    ;;    associated value access in JS
    (:bar foo) ;; => foo["bar"]
That seems pretty close to what's expected though, doesn't it?


I'd expect `(:bar foo)` to desugar to `foo["bar"]()` since the keyword is being used as a function. Property access in clojurescript uses the ugly `(.-bar foo)` syntax.


No, to get foo["bar"]() in CLJS you write ((:bar foo)). :bar in this case is a function, which returns a value by a key ":bar" from "foo", it's not a property.


Those are 3 distinct types in Clojure; unfortunately they have no equivalents in JavaScript, thus they become strings.


To my knowledge, keywords are actually functions in Clojure, which do have an equivalent in JS. "Looks more like Clojure" seems like a good enough reason to me.


Keywords implement many interfaces, function (IFn) being one of them. See this line in the clojure source code:

  public class Keyword implements IFn, Comparable, Named, Serializable, IHashEq 
https://github.com/clojure/clojure/blob/master/src/jvm/cloju...


They can be used as functions, but I think they're implemented differently for optimization. Could be wrong.


I'm not sure because I don't know anything about this language or clojurescript, but I do know clojure and I'll explain the differences in terms of that.

    \a ;; becomes 'a' in java.  The character of 'a'
    :a ;; a keyword of :a. More efficient than using 'a'.  Also it can act as a function.  If you have a map with a key of :a in it, instead of having to say "get me the value for :a" you can say (:a map)
    "a" becomes "a" in java.  The string of "a"


In clojurescript strings are just sequences of characters where characters are expressed as \a and strings as "foo". In JS single char string is an equivalent of a character, as a side effect \a and "a" compiles to a same thing, which BTW matches behavior of clojurescript as well. Main reason for \a like character types existence is clojure(script) compatibility and nothing more.

As of :a keyword it's a different story. As a matter of fact actual (quoted) keyword ':a does not compiles to "a" string, but general references do. That is because in JS constant string literals like "load", "DOMContentLoaded" are used in cases where idiomatic Clojure(script) would have used :load :DOMContentLoaded keywords, there for it made sense to just compile those keywords to semantical analogues in JS, same as `foo-bar` lisp naming convention compiles to adequate `fooBar` naming in JS.


This is really cool. I've always been a fan of lisps, but not to the point of picking them up. Building for the web using a lisp has always seemed difficult due to (perceived?) lack of tooling, documentation, and community. JavaScript is for the web like no other language, and Wisp looks like it makes building web projects in a lisp a reality. Kudos!


If you're interested in building for the web in a Lisp, you should seriously give Clojure a try!


This is the first lisp dialect which I can make sense of with just light reading. It's simple enough that I actually tried it and liked it. The output is fairly clean JavaScript which helps in learning and reduces barriers.

As a non-lisp guy who doesn't know any better (me), good job.


This reminds me of ParenScript http://common-lisp.net/project/parenscript/

Which is basically a subset of common-lisp that compiles to human-readable javascript. It's a good idea.


One idea: - A major drawback to using generated javascript is that line numbers in error messages don't relate to your original source files. Perhaps a debug option to add line number comments in the generated code?


Or even better, source maps support.


Adding source maps support to wisp is my no 1st priority for wisp.


Does Wisp have any facility for namespaces - I didn't see anything about that in the link?



They have being added recently and more clojure compatibility is planned for the future.


Personally, I'd rather see lisp with JS syntax (CoffeeScript would be even better)


What does that even mean?


Dylan


You know, it's like French with Chinese syntax.




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

Search: