Hacker News new | past | comments | ask | show | jobs | submit login

If no other language has any functionality similar to how Clojure does things then I think we'll need references to explanations or videos before we can even begin to understand your claims!



Clojure is following in the tradition of lisps that do this right. The important bit is the extra indirection on top-level names. I wrote more about it here a long time ago: https://www.brandonbloom.name/blog/2012/12/21/the-nodejs-rep...

Also interesting is the other end of the spectrum: Forth. Instead of mutation, offers snapshots and restores of the “dictionary”. See this video: https://youtu.be/mvrE2ZGe-rs


I don't fully understand what you're getting at. It would have been nice to see no examples with code entered at a REPL and the results, in both JS and Clojure, say.

Are you saying that you want to be able to make bindings that are refreshed on REPL reload? For example if I have a file that contains

    x = 1
and in my REPL I write

    y = x + 1
then I change my file to say

    x = 10
and reload the REPL then y is 11?


Well, the three key aspects, in my preference order, are:

1. Server repl with editor integrated clients. So your text buffers in your favorite editor is the repl. Look at the gifs here https://atom.io/packages/proto-repl to give you an idea for it.

2. Reifed language constructs. You can read about it here http://www.lispcast.com/reification . An easy example is if you have fn A depend on B. If you change B and call A, A will use new B. That's because the information is still availaible at runtime for A to figure out the latest version of B when calling it.

3. Functional programming / emphasis on small independent code blocks that compose. This is where you hear things like immutability, functions that take functions, purity, side effect free, managed references, etc. Basicly state in Clojure is hard to corrupt. That means if you alter state in your repl, it rarely messes up the full state, allowing you to keep working long sessions with your app state still being valid and usable.

I don't have a link for #3. So I'll give an example. Say you have a map you want to add data too. Say this map is read by something else, but you want to try adding something deeply nested to it. In Clojure, you can try as much as you want, experiment until you succeed to mold the map the way you wanted. The other thing reading the map never saw any of your changes, because it sees an immutable view of it. So after your done, if you use that other thing, it'll still work, because you didn't mess up the state it was depending on.


Thanks, that's very helpful.

As a Haskell programmer I already know the benefits of 3! 1 and 2 are things that I don't take advantage of so I have a couple more questions.

1. Is this like a Jupyter notebook or some different sort of functionality?

2. Does it work for integer values, say, as well as functions? Suppose my source code says

    x = 1
and in my REPL I write

    y = 10 + x
and then I change my source code to

    x = 2
and reload the REPL. Then is y 11 or will y be updated to 12?


Is this like a Jupyter notebook or some different sort of functionality?

Its similar in some ways, but not quite exactly the same thing. The repl is a server, and doesn't have an interface. So it reads over a socket port, and prints a response back over the socket using a common protocol. So you can build any client you want for it. What is most common is to take an existing editor, like emacs, vim, eclipse, atom, etc. And write a plugin for them which interacts with the server repl. So say your in eclipse, you have a Clojure project open, you can have eclipse send your project code to the repl for you. In practice that means you just work on your code files directly, and just sync them to the repl as you go. Some clients try to be even fancier, creating visual representation of code output like graphs, or gui controls like drilling into a nested map.

Does it work for integer values, say, as well as functions? Suppose my source code says

Y would be 12.

(let [x 1 y (+ 10 x)] y)

If you load this it'll return 11. If you change x to 2 and reload this, it will return 12.

Globally you'd do:

(def x 1) (def y (+ 10 x)

Now y is equal to 11. If you change x to 2, and only reload x, y would still be equal to 11. You'd have to reload y also if you want it to be 12 now.

That's because y is bound to the value of the expression, not to the expression itself. And the value is calculated at load time.

Now you could bind it to the expression by using a function.

(def x 1) (def y #(+ 10 x)

#() is Clojure's shorthand for lambda.

So now the caller is in charge of deciding when to evaluate y.

Calling: (y)

Would return 11 and if you change x to 2, calling it again would return 12.

You can also use reactive constructs instead. So when setting x to 2, an event is published, so you can listen to it and have it reset y to the new value of evaluating (+ 10 x).


    (require '[foo :refer [f]])
    ; edit f in foo.clj
    (require '[foo :reload])
    (f 1) ; should call NEW f.
Node doesn’t have a reload construct. If you hack it in by mucking with the module cache, you still won’t get the new f in your module’s local copy of it.


But doesn't the same apply for integer too, as in my example? After reloading y should refer to the NEW x?

And what should happen in your example if f were deleted?


If f were deleted, it would still be in memory unless you explicitly call ns-remove to clean it up. In practice, this is rarely an issue, but I do wish the experience was a little cleaner there.

The same things do apply to integers, but if you use them at the top level (outside a function) then they will be dereferenced immediately (there is no delayed function body to wait for) and so you will get the initial value only once. If you want to enforce a delay, you can use (var x) or the shorthand #’x and later derefence that with @


Other languages do, like Common Lisp, Racket, and most other Lisps. I hear dylan and smalltalk do to, but I don't have first hand experience.

This page https://clojure.org/about/dynamic explains it well.

The difference basically is that the mindset is to work within a running environment, swaping things out as its running. Its closer to a Jupyter notebook, or an excel sheet in some ways, if that helps you visualize it.




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

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

Search: