Live data from Hacker News

Dueling Rhetoric of Clojure and Haskell

tech.frontrowed.com

91–100 of 107 posts

Re: Dueling Rhetoric of Clojure and Haskell

#91
post #45

Earlier quoted context omitted.

The Haskell REPL is pretty good for a static language, but the experience is dramatically different to how a Clojure programmer would use want to use it. To be fair, Node and Python also have totally not usable REPLs for this style.

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!

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.

Re: Dueling Rhetoric of Clojure and Haskell

#92

Earlier quoted context omitted.

The Haskell REPL is pretty good for a static language, but the experience is dramatically different to how a Clojure programmer would use want to use it. To be fair, Node and Python also have totally not usable REPLs for this style.

GHC's repl is completely fine. The thing with dynamic languages is that the development style is basically println-driven. It goes like this: because you can't keep anything longer than a 1-page script in your head and because you can't remember the APIs of other people and hence you can't trust anything you write, in order to keep some sanity, you have to execute every freaking line of code that you write in order t…

Since your specific about your statically typed language, which I'm assuming you mean Haskell. Are you also specific about your dynamically typed language? Are you talking specifically of Clojure?

Its unfair to club Clojure and imperative object oriented dynamic languages together. The same way its unfair to club Java and Haskell together.

You're right about the print-ln style. You do run your code everytime you touch a single line. That's what I like about it. But its a personal preference, like some people prefer to compose music on a sheet, others rather have their instrument in hand.

And you're forgetting the trade offs. With haskell, you wrestle the compiler, and every line you write has a compile error at first, until you get it right. This takes as much time if not more, at least for me, then it does running each of my lines of code in my REPL.

I guess I fall in that category where I kind of enjoy the beauty of both, though at the end of the day, I find myself having more fun coding when writing Clojure.

I've never suffered from a Clojure refactoring. You have to be a little more careful, but its never been that painful to me. Again, could be how I perceive "coding pain" is different from others.

Re: Dueling Rhetoric of Clojure and Haskell

#93
post #55

Earlier quoted context omitted.

These are old tired arguments. I prefer being forced to keep my program simple by making complexity intolerable over encapsulating it. Your preference may differ. I find I have to refactor my dynamically typed programs less frequently than my statically typed ones. Your mileage may vary. No amount of type safety will prove my game is fun, or that my user can understand the UI. I want fast iteration times, since I can…

> No amount of type safety will prove my game is fun, or that my user can understand the UI No, but what it can ensure to some extent is that your game runs , and doesn't crash randomly. If the game crashes constantly, no one is going to play it no matter how fun it is.

to some extent

That's the keyword here. Maybe I'm missing critical data, but I've never perceived the reduction in defect from Clojure to Haskell. I've looked for studies on it, and they all point to either no difference or incredibly close. Never I've been shown a case where the reduction in defects would have an impact on the business I work for. Enterprise software is a domain that isn't that sensitive to defect. Anything less then 5% difference would go unnoticed, and affect in no way sales.

My conclusion, it comes down to your own enjoyment. Which one do you have more fun using and are the most productive in, that's the one you should be using.

I allow muself to change my mind if Haskell really proves to be 10% to 30% or more lower defect, maybe in a later version, with some GHC extension, maybe liquid haskell, I'm not closing my mind to it if it happens I'll be there.

Re: Dueling Rhetoric of Clojure and Haskell

#94
post #77

Earlier quoted context omitted.

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?

(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?

Re: Dueling Rhetoric of Clojure and Haskell

#95
post #79

Earlier quoted context omitted.

This is a rather glib response. Of course one should choose the right tools for the situation. Personally if I'm prototyping an algorithm I'd rather do it with types so I don't write any code that was clearly nonsense before I even tried to run it.

Personally, I work the same way you do. But I've heard enough people who want the faster feedback of a REPL-like environment to accept that their approach at least feels more productive to them. It may even be more productive - for them. If so, tying them down with type specifications would slow them down, at least in the prototyping phase.

That certainly seems like a reasonable hypothesis to explore and I'm curious to try a Haskell "EDN"-like type as defined in the article to see if that helps me prototype faster!

Re: Dueling Rhetoric of Clojure and Haskell

#96
post #73

Earlier quoted context omitted.

Then I think you're really going to need to educate us about what EDN really is ...

Educate yourselves. https://github.com/edn-format/edn/blob/master/README.md#tagg...

> edn supports extensibility through a simple mechanism. # followed immediately by a symbol starting with an alphabetic character indicates that that symbol is a tag

OK, so it's trivial to add that as a constructor to the Haskell EDN type in the post, and you can even support it in JSON with a dictionary like

    #myapp/Person {:first "Fred" :last "Mertz"}
is represented as

    {"#myapp/Person" : { "first" : "Fred", "last" : "Mertz" } }
What are the remaining objections?

Re: Dueling Rhetoric of Clojure and Haskell

#97
post #77

Earlier quoted context omitted.

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.

Re: Dueling Rhetoric of Clojure and Haskell

#98
post #97
post #77

Earlier quoted context omitted.

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…

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?

Re: Dueling Rhetoric of Clojure and Haskell

#99
post #96

Earlier quoted context omitted.

Educate yourselves. https://github.com/edn-format/edn/blob/master/README.md#tagg...

> edn supports extensibility through a simple mechanism. # followed immediately by a symbol starting with an alphabetic character indicates that that symbol is a tag OK, so it's trivial to add that as a constructor to the Haskell EDN type in the post, and you can even support it in JSON with a dictionary like #myapp/Person {:first "Fred" :last "Mertz"} is represented as {"#myapp/Person" : { "first" : "Fred", "last" :…

EDN is much more like XML than it is JSON.

1) When I read #uri "http://google.com" my app code sees (java.net.URI. "http://google.com"), not Tag "URI" "http://google.com" or whatever. clojure.core/map does not see tagged values, it does not know that the values were ever read from edn.

2) Extension happens in userland library code, you don't need to go modify the hardcoded pattern match in core. (Talking about reifying actual instances that we can code to, not reader tags)

3) Data is just information. Information isn't coupled to code, it's abstract values, totally separate from the concrete implementation. As RH says: "code is data. But data is not code until you define a language around it." Typeclasses are about code.

4) EDN values are cross platform and a platform's EDN reader can reify the value into an idiomatic type for that platform. E.g. a haskell edn reader could reify #error "foo" into Left String; a Java reader a Throwable to be re-thrown later.

5) The whole prism diversion is sophomoric. Once you've read the EDN into concrete values of whatever platform type, you can use whatever platform abstractions you like to manipulate them. Clojure has lenses too: http://funcool.github.io/lentes/latest/#composition

You can watch the EDN talk or read the transcript if you'd like to learn more. This topic is very deep but this thread is not doing it justice.

Re: Dueling Rhetoric of Clojure and Haskell

#100
post #96

Earlier quoted context omitted.

> edn supports extensibility through a simple mechanism. # followed immediately by a symbol starting with an alphabetic character indicates that that symbol is a tag OK, so it's trivial to add that as a constructor to the Haskell EDN type in the post, and you can even support it in JSON with a dictionary like #myapp/Person {:first "Fred" :last "Mertz"} is represented as {"#myapp/Person" : { "first" : "Fred", "last" :…

EDN is much more like XML than it is JSON. 1) When I read #uri " http://google.com" my app code sees (java.net.URI. " http://google.com" ), not Tag "URI" " http://google.com" or whatever. clojure.core/map does not see tagged values, it does not know that the values were ever read from edn. 2) Extension happens in userland library code, you don't need to go modify the hardcoded pattern match in core. (Talking about re…

I think it would be a great service if someone would write up a technical introduction to this for non-Clojurists. You seem to be communicating a subtle point that not many of us are getting ...
Post reply on HN