News for hackers. Stuff that matters.
Re:Clojure will affect the way you think about programming by keymone on Friday August 04, 2017 @09:58AM (#14928673)
Clojure is the language where LISP clicked for me. Can't recommend it enough, it's got all of it - immutable datastructures, convenient data literals, simple and composable concurrency primitives, very thin interface to host VM.

Just put enough effort to get beyond that "omg parenthesis" barrier and it will be a delight. It's like that Half-life joke: there are two kinds of people, those that finished Half-life many times and those that never got off the train (which as somebody will probably point out, is a variation on another joke, but you get the idea).

totally unaffiliated: https://www.braveclojure.com/clojure-for-the-brave-and-true/

Re:Clojure will affect the way you think about programming by arximboldi on Friday August 04, 2017 @10:35AM (#14928938)
There are many things to love in Clojure, like core.async, the lispyness, etc. But for me, their biggest breakthrough is with no doubt the data-structures.

Clojure default of immutable hash maps and vectors was really bold. They had to innovate by giving a twist to Bagwell's great research on data-structures, and they managed to build what in my opinion are the first set of general data-structures suitable of representing traditional hierarchical object-tree data-models immutably, at the scale of large interactive software.

Without these, the single-atom architecture that now is popular as ever with Redux, Elm, etc. would not be possible. The flourishing of functional programming for interactive software that followed shows to me that the biggest impediment before was not the lack of functional ways of expressing interactions (the Haskell people have devoted a lot of notable effort in the FRP camp). Instead, just having efficient data-structures to write persistent document models, escaping the rigidity of lists and rb-trees, allows you to write big interactive sofware in a functional manner even with the most dumb abstractions (which is a good thing, KISS!) and even stupid language (JavaScript!).

This has inspired me to work on a generic implementation in C++, which also has experimental Python and Guile bindings: https://sinusoid.es/immer/ https://github.com/arximboldi/immer/

In the past I also did some other work on bringing Clojure Transducers to C++ (https://www.youtube.com/watch?v=vohGJjGxtJQ&t=1614s) but I know consider it a much less important effort---without the data-structures the other parts of Clojure feel almost like just sugar.

EDIT1 -- Sorry for the shameless plug ;)

EDIT2 -- Grammar

Re:Clojure will affect the way you think about programming by KirinDave on Friday August 04, 2017 @11:59AM (#14929645)
> In the past I also did some other work on bringing Clojure Transducers to C++ ... consider it a much less important effort---without the data-structures the other parts of Clojure feel almost like just sugar.

Very few clojure programmers consider Transducers very important even in Clojure. While they're convenient for implementing Clojure's stdlib and they have some nice properties, they're very difficult to work with. It takes a very experienced clojure programmer to use transducers. Heck, I know some famous clojure developers who admit they themselves don't feel confident using them.

But the main challenge for them is that transducers just scream for some basic type validation so that you don't accidentally chain together nonsense. C++ could provide that, and you'd end up with all the same properties. In particular, they offer something like half the monad laws and a more easily composed form of CPS (how your continuation is called is more predictable).

I'd think that might be a really valuable thing in C++, as it's a construction that reproduces stream fusion.

Re:Clojure will affect the way you think about programming by arximboldi on Friday August 04, 2017 @02:34PM (#14930835)
Yeah, I agree!

Actually one of the things I found during my work on transducers is that actually they seem to me more implementable in C++ than in Haskell. For example, you can implement state-less transducers with almost zero overhead, something that in Clojure is definitely not true (so the standard transducers do hide state inside the closure of the reducing functions). It is also easier to do n-ary transducers for zipping and unzipping and everything, as you intuit, is type checked.

Still, I agree that transducers are most useful when you have libraries that make sense of them. For example, you could implement a lot of "Rx" using transducers. Ideally I see a user never writing a transducer, and occasionally passing one to some library that provides "higher order" reactive collections (channels, observables, etc.) that can be transformed with transducers. For example, my motivation to implement them in C++ was to build "observable/reactive lenses" (something like "cursors" in Om) [1] where you could use transducers to specify how you "zoom" into the virtual sequence of state values...

Anyways, they are an interesting coding tool, but they don't really influence the architecture of the application.

[1] atria::funken https://github.com/Ableton/atria

Re:Clojure will affect the way you think about programming by KirinDave on Friday August 04, 2017 @06:14PM (#14932803)
> they seem to me more implementable in C++ than in Haskell

If you don't mind the overhead, it's ContT wrapping some base monad. Or you could make it integral. That is more specific than transducers, I grant. But there's not much they can do that ContT over like Array does not.

I think it's too bad they were invented in Clojure, because they're brutally hard to use right and write in clojure.

I have some interesting work I could share in private on using them to provide stream fusion properties to pipelines of channels. Hit me up on keybase if you'd like to see. I don't want to open source it because then people will expect me to explain them and maintain them and I don't feel like it :)

Re:Clojure will affect the way you think about programming by arximboldi on Friday August 04, 2017 @08:19PM (#14933461)
Sorry, I actually meant "than in Clojure". You are right about the ContT. I'm actually curious about your transducer based stream fusion stuff... I'll hit you up later about it :-)
Re:Clojure will affect the way you think about programming by lgas on Friday August 04, 2017 @02:31PM (#14930807)
You might find this work on composable well-typed transducers in Idris interesting: https://deque.blog/2017/08/04/transducers-in-idris-2/
Re:Clojure will affect the way you think about programming by usgroup on Friday August 04, 2017 @01:38PM (#14930399)
Know what you mean RE transducers. I still haven't come to a point where using the transducer pattern is more convenient than just (partial map f) tbh.

Yet to dare clojure spec but it feels likely that the next mind blowing journey will be therein.

Re:Clojure will affect the way you think about programming by chpill on Friday August 04, 2017 @01:59PM (#14930569)
Writing your own transducers is hard and error prone, but I think using and composing the ones given you by clojure.core is actually rather easy (Especially using the 3 arity of `into`).

I don't use so many `->>` anymore thanks to them.

Re:Clojure will affect the way you think about programming by KirinDave on Friday August 04, 2017 @02:07PM (#14930617)
I dunno. Except for one very specific project, I've yet to see a "Wow!" use case for transducers. The only place where they really shine is working with channels, but I think channels are a big design mistake (after extensive work trying to tame them).
Re:Clojure will affect the way you think about programming by arximboldi on Friday August 04, 2017 @02:44PM (#14930925)
Interesting! Why do you think they are a big design mistake? I can understand how they can be misused, but I find myself missing them in every language I used that doesn't have them...
Re:Clojure will affect the way you think about programming by KirinDave on Friday August 04, 2017 @06:16PM (#14932824)
So either I'd rather talk about the COMPUTATION and resource safety rather than the channel, as in Pipes/Conduit/Streaming from haskell.

OR, I'd rather deal with a direct actor model a la Erlang, Pony and Cloud Haskell.

Go's experience is so goddamn miserable it should just put the entire notion of async channels as a higher level programming library to bed. As a low-level primitive, it's okay but not fundamental.

Re:Clojure will affect the way you think about programming by tome on Friday August 04, 2017 @11:03AM (#14929183)
Do you know of a good resource for reading about their data-structures, especially anything Haskell doesn't have?
Re:Clojure will affect the way you think about programming by DigitalJack on Friday August 04, 2017 @11:25AM (#14929372)
Any book on clojure and website too will go over them. They are fundamental to using clojure.

I don't know enough about haskell to say what it does or doesn't have in relation to clojure. However, it's not simply the data structures, but how the language is built to interact with them from a programmers perspective.

From a user interface to the language point of view, I find the ways of interacting with maps to be very nice.

In particular the dual purpose of "keywords" to serve both as a good index/key in said hash maps, but also as callable look up function for the same key in a hash map leads to simplified code.

This, coupled with the extremely high usage of those maps in typical clojure code, makes a big difference.

To expand on that a little, "keywords" are symbols that begin with a colon, which I believe is the same as common lisp. :for :example :this :is :a :sentence :of :keywords. They are commonly used as the key in a map. Which has a literal syntax like (def map1 {:a 1 :b 2 :c "taco"}). To pull a value out, you can evaluate (:c map1) which will return "taco".

They are hash maps based on work by Philip Bagwell, and I think a lot of languages have versions of this now. At least scheme and Common Lisp do. But I don't believe they have the nice literal syntax and interaction syntax.

Many Lisp traditionalists are bothered by the use of curly braces for maps and square brackets for vectors, however I'm a fan. Without this bit of syntax, you have to add verbosity to the language to differentiate defining a map from doing a lookup, etc.

For resources, Clojure for the Brave and True is pretty popular. Also the online community is quite friendly, although I have noticed some trends toward "the one true way" of doing things that puts me off a little.

Re:Clojure will affect the way you think about programming by madmax96 on Friday August 04, 2017 @02:49PM (#14930967)
>Many Lisp traditionalists are bothered by the use of curly braces for maps and square brackets for vectors

I have definitely seen this. I'm not sure that I understand this sentiment. The only thing that Clojure is missing is the "system" feel that Common Lisp provides, with things like character macros, symbol macros, etc.

That being said, I definitely appreciate how thought through Clojure is, especially when compared to CL. Several things are missing/don't feel well thought out in CL (notion of a `calleable` type is gone, `nth` isn't defined on vectors or strings (but you can still `length` them!) nor is `first` and `rest`) That provides a great deal of friction.

Re:Clojure will affect the way you think about programming by lispm on Saturday August 05, 2017 @03:39AM (#14934637)
Common Lisp had a lot thought put into it, but the design goals were different. One of the design goals was to support efficient compilation given various constraining dimensions: the need for speedy compilers vs. the need for delivery of applications on standard hardware. Thus a Lisp compiler should be able to generate fast code, even by using whole-program compilation. Thus the language has to take care of a wide range of possible implementations, not just one on a particular virtual machine.

Clojure OTOH has a relatively straight-forward compiler written in Java, only targetting the JVM in a standard way. The Java/JVM infrastructure for code generation (JIT), low-level optimizations (JIT), memory management, application building and delivery could be reused. With all its features and limitations (for example no TCO, fixed JVM instruction set, ...).

Common Lisp also not only provides some generic operators, but also lots of non-generic operators. One reason for that is the will for backwards compatibility (which was another goal in the Common Lisp design) and the idea that something like Common Lisp is also a low-level languages or provides at least a layer of low-level stuff, functions you would use to implement higher-level stuff.

Common Lisp is the next step in the evolution of Lisp I to Lisp 1.5 to Maclisp to Zetalisp. Thus it contains much of the core Lisp functions, stuff you can read about it the Lisp manuals from 1958 and 1960. People did not want to throw their code away, they wanted a modernized Maclisp. Thus one could port a 100kloc Lisp program from Maclisp or Zetalisp to Common Lisp without too much effort. The main operations were there.

Clojure OTOH has almost no backwards compatibility to earlier Lisp dialects. Programs can not be ported from Lisp to Clojure in a useful way. They have to be rewritten. But that was okay, since the main target were not Lisp developers, but people who wanted a language with Lisp influence in the Java/JVM eco-system (or possibly other eco-systems too).

Thus Common Lisp looks to you like it has less thought put in, where people actually struggled to be backwards compatible and modernize the language at the same time.

So Common Lisp has lots of non-generic functions, a layer of generic non-extensible functions (like the sequence layer) and a mechanism for extensible generic functions (CLOS). Something like CLOS is implemented on-top of the non-generic Lisp, with a few parts using implementation specific mechanims. One does not need to use the primitives of a different host language, because Common Lisp is already capable of hosting with its primitives.

Re:Clojure will affect the way you think about programming by kbp on Friday August 04, 2017 @05:39PM (#14932536)
> notion of a `calleable` type is gone

You can do this using the metaobject protocol and defining a class with a metaclass of FUNCALLABLE-STANDARD-CLASS, for example, given:

    (defclass c ()
      ((x :initarg :x :accessor x))
      (:metaclass funcallable-standard-class))

    (defmethod initialize-instance :after ((c c) &key)
      (with-slots (x) c
        (set-funcallable-instance-function
         c
         #'(lambda ()
             (format t "~&I'm #~a" x)))))
Then (funcall (make-instance 'c :x 3)) will print "I'm #3".

> `nth` isn't defined on vectors or strings (but you can still `length` them!)

ELT in Common Lisp is generic over sequence types. NTH is specific to lists. If you want to write a function that is generic over sequences, use ELT. If you know that you have a list or an array, and you're writing something performance sensitive, you can avoid type dispatch overhead by using NTH or AREF instead of ELT.

> nor is `first` and `rest`

You can avoid that friction a lot of the time by writing in terms of MAP, REDUCE, REMOVE-IF-NOT, and so on, as well as LENGTH and ELT, which are all generic over sequences, or doing (iter (for x in-sequence sequence) ...) or whatever.

But if you really want to use FIRST and REST to walk through a vector, you can do (coerce vector 'list) first to convert it. Coercing a list to list will just return that list, so that version would work for either, too. I admit, there's no real reason I know of (aside from lack of demand) that there isn't a predefined function like:

    (defun vector-rest (vector)
      (make-array (1- (length vector))
                  :displaced-to vector
                  :displaced-index-offset 1))
Then if it bothered you you could do something like

    (defun head (sequence)
      (elt sequence 0))

    (defun tail (sequence)
      (etypecase sequence
        (list   (rest        sequence))
        (vector (vector-rest sequence))))
Re:Clojure will affect the way you think about programming by flavio81 on Friday August 04, 2017 @04:46PM (#14932097)
> Many Lisp traditionalists are bothered by the use of curly braces for maps and square brackets for vectors, however I'm a fan. Without this bit of syntax, you have to add verbosity to the language to differentiate defining a map from doing a lookup, etc.

I agree with you, in the sense that they are useful, however the complain of "Lisp traditionalists" will be that in any case, if you need them, you can add them to Common Lisp by using reader macros. So in CL the curly braces and brackets are "free" to be used (i.e. define what they should do) in any way you want; on Clojure they are already taken, so it feels a bit uncomfortable.

Re:Clojure will affect the way you think about programming by kazinator on Friday August 04, 2017 @07:05PM (#14933096)
> To pull a value out, you can evaluate (:c map1) which will return "taco".

Not (map1 :c)? A bit odd.

Re:Clojure will affect the way you think about programming by DigitalJack on Saturday August 05, 2017 @12:39PM (#14936537)
Both work I believe, but the idiomatic way is keyword first.
Re:Clojure will affect the way you think about programming by wging on Friday August 04, 2017 @11:26AM (#14929377)
Here is a good resource on Clojure's persistent vector type: http://hypirion.com/musings/understanding-persistent-vector-...
Re:Clojure will affect the way you think about programming by mej10 on Friday August 04, 2017 @11:31AM (#14929422)
Hash Array Mapped Tries are what underly the default maps in Clojure: http://lampwww.epfl.ch/papers/idealhashtrees.pdf

They are pretty amazing. Of course there are implementations in Haskell now, but the reason they are especially cool in Clojure is how well they integrate with the language and its other features.

Re:Clojure will affect the way you think about programming by jasonkostempski on Friday August 04, 2017 @12:11PM (#14929749)
I think Bitmapped Vector Trie [1] might be some novelty introduced by Clojure.

[1] https://stackoverflow.com/questions/8844707/how-is-a-bitmapp...

Re:Clojure will affect the way you think about programming by arximboldi on Friday August 04, 2017 @02:36PM (#14930855)
Search "Phil Bagwell", most of his papers are quite interesting.

If you allow me another shameless plug, I also compiled a good bunch of references in the "Related Work" section of my own paper on immutable vectors: https://public.sinusoid.es/misc/immer/immer-icfp17.pdf

Re:Clojure will affect the way you think about programming by robto on Friday August 04, 2017 @12:43PM (#14929935)
Here's a blog post[0] from the guy who implemented Lean Hash-Array Mapped Trie (HAMT) maps for clojurescript. It's really cool stuff!

[0] https://bendyworks.com/blog/leveling-clojures-hash-maps

Re:Clojure will affect the way you think about programming by KirinDave on Friday August 04, 2017 @12:00PM (#14929658)
Folks have linked you to the paper and mentioned tutorials.

You might also Okasaki's Purely Functional Data Structures, which ends up in the citations for a lot of these.

Re:Clojure will affect the way you think about programming by arximboldi on Friday August 04, 2017 @02:42PM (#14930909)
Okasaki's work is really interesting, and it is quite mind-blowing the theoretical properties he achieves by exploiting laziness and so on. At the same time: those data-structures have one fundamental flaws they have high constant factors, specially outside of Haskell. That was Phil Bagwell + Rich Hickey revolutionary contribution in my opinion... finding data-structures that are rather simple yet but work well in practice because they make the right engineering trade-offs and work well with CPU caches, etc.
Re:Clojure will affect the way you think about programming by cle on Friday August 04, 2017 @10:15AM (#14928802)
I've learned to love the parentheses, because they embody what is so nice about lisps (and particularly Clojure)--inside the parentheses is a little nugget of functionality that generally stands on its own. No syntactic tricks, the only "trick" is the macro system, but it's so straightforward that I'm not sure I'd call it a "trick".

The other immediate barrier is when Clojure barfs an ugly stack trace. I've heard that 1.9 will address that with core.spec, but I haven't explored it yet.

Re:Clojure will affect the way you think about programming by agumonkey on Friday August 04, 2017 @10:55AM (#14929113)
hmm sexy idea to have spec help for stacktrace. I expect something cute like elm error messages.

About the parens, it's true it's one great thing, every construct has a value [1].

It's funny because You hear about object orientation where things are uncoupled and standalone yet the language isn't this way. Lisp has this, it's the incarnation of its own idea. But it looks silly if you're in it for the syntactic appeal.

[1] Although I often wish for a helper thing when evaluating the body of, say a let to grab the bindings instead of saying "unknown var a in (inc a)". This is lisp in general

Re:Clojure will affect the way you think about programming by DigitalJack on Friday August 04, 2017 @11:30AM (#14929416)
stack traces still suck as far as I've seen on the 1.9 alpha branch. And while clojure spec is pretty neat, the barge-load of information it dumps on a spec failure is overwhelming.

That said, the info it dumps is in the form of clojure data structures. In my own programs, I've added code to refine this output to something useable, but it's particular to my project and I don't think generally useful.

There are other projects to aid in this fashion too. Expound is one that takes inspiration from Elm, and Inspectable is intended to help at the repl by launching a gui for exploring Specs and failures.

I've tried both, but couldn't get inspectable to work in my environment, and expound isn't meant to handle the error I've been dealing with, so I can't speak to either.

Re:Clojure will affect the way you think about programming by bbrinck on Monday August 07, 2017 @09:07AM (#14947195)
"expound isn't meant to handle the error I've been dealing with"

If you have some time, would you be willing to expand on this? I'm curious to learn more about your error. I'm the author of Expound so I'd like to make it more useful (or, at least, understand the limits of a library like Expound).

Re:Clojure will affect the way you think about programming by phyrex on Friday August 04, 2017 @01:47PM (#14930485)
Expound recently made my life a lot better by cutting through one of those ridiculous spec errors and telling me exactly what was wrong! I was really impressed.
Re:Clojure will affect the way you think about programming by Nekorosu on Friday August 04, 2017 @10:26AM (#14928873)
Clojure is more than Lisp and less than Lisp. I love it for the "more" part.
Re:Clojure will affect the way you think about programming by _t0du on Friday August 04, 2017 @12:15PM (#14929780)
I keep hearing this sentiment, moreso than I've ever seen for any other language. Once you "get into" Clojure, you're both A.) Extremely productive with it, and B.) in love with Clojure.

How does it hold up for those of us that really love static typing and compilers?

Re:Clojure will affect the way you think about programming by christophilus on Friday August 04, 2017 @09:07PM (#14933661)
I love static typing. I really dislike almost every dynamic language I've ever worked with. But Clojure is currently my favorite language. I've done C#, F#, Go, JS, Ruby, Dart, C, C++, dabbled in Haskell, OCaml, purescript, D, Nim... (I like programming.) Anyway, once I dove into Clojure, I couldn't go back to any other language. I do wish it was more general purpose (not so slow to boot, had a decent native / non JVM, non JS target.)
Re:Clojure will affect the way you think about programming by taylodl on Tuesday August 08, 2017 @06:42AM (#14956391)
You should check out Ferret: http://ferret-lang.org. It compiles to C++11. I haven't tried it myself yet, so I don't know its limitations.
Re:Clojure will affect the way you think about programming by keymone on Friday August 04, 2017 @03:08PM (#14931132)
the static typing part - yeah, you just have to try and let go. there is typed.clojure for gradual typing though last time i checked it was quite slow. clojure.spec is a great attempt at bringing some discipline and provides quite a bit more than your usual typing system can do, though not entirely on compilation level.

as for compiler part - you're in for a treat. clojure is a compiled language - everything compiles down to jvm bytecode. the surprise part is that due to homoiconicity you get a compiler that's happy to let you hook into particular pieces of your code and (since code is literally represented as usual clojure data structures - lists/maps/vectors/etc) modify it on the fly before compiling. you basically define `f(code) -> other_code` - the ultimate metaprogramming.