13 ms·
Clojure 1.7 is now available
- 27182818284 11y ago>Transducers are composable algorithmic transformations. They are independent from the context of their input and output sources and specify only the essence of the transformation in terms of an individual element. Because transducers are decoupled from input or output sources, The biggest thing holding me back from learning Clojure is that I fear it will take me a decade to become remotely competent in it.
- fnordsensei 11y agoDon't worry too much if you don't get the esoteric stuff in the beginning. The fact that it's there just means that there's room to grow. The core language is actually very simple and quite straightforward. It just allows for some quite mind-boggling stuff. Try Carin Meier's Living Clojure if you feel up for an intro.
- akilism 11y ago2nd for Living Clojure. Great crash course in Clojure for working developers.
- akilism 11y agoMight as well check out Joy of Clojure by Michael Fogus also, really good book.
- puredanger 11y agoAnd then check out the new Clojure Applied (by me) which aims to be a good intermediate level intro. https://pragprog.com/book/vmclojeco/clojure-applied https://pragprog.com/book/vmclojeco/clojure-applied
- mark_l_watson 11y ago+1 I looked at your table of contents: nice topic selection. The free excerpt was a good read. You might edit your comment to provide a direct link to that.
- jwhitlark 11y agoClojure Applied is an excellent book so far. I've been using Clojure for a long time, and it's still been very helpful in updating idioms for modeling domains, composing applications, etc. I'd say it's required reading for working Clojure programmers, of any experience level. We really needed a "how to build applications in Clojure" to complement all the "how to do stuff in Clojure" books that are already out.
- dkersten 11y agoYou don't need to learn every feature to be competent in the language. Some features are advanced features that are not required in day-to-day programming (eg, transients, you can go forever without ever touching them, but if you need performance they're there). A lot of the advanced things are of most interest to library authors.
- pron 11y agoIt is one of the simplest and easiest languages around. The addition of transducers is an unfortunate case of Clojure "pulling a Haskell", valuing an elegant abstraction over ease of understanding and learning. Indeed, your comment alone shows that doing them (and especially giving them a high profile) was a mistake. Just because you can abstract something elegantly doesn't mean you should. No beautiful abstraction is worth scaring people away. Fortunately, Clojure doesn't make many such mistakes, and it usually tries to err on the side of pragmatism. I hope transducers aren't the beginning of a trend. But just don't use transducers until you feel comfortable enough with the language. They're not an essential feature.
- kyllo 11y agoI don't understand this argument. Clojure shouldn't have transducers because the word sounds scary? Programming language designers should avoid adding powerful, higher-order abstractions because they are hard to understand? This sentiment is incredibly anti-intellectual. And like you said, if you don't understand it you don't have to use it.
- leishulang 11y agoEveryone who is learning Functional programming should be able to use map/reduce well. With that, understanding transducers is just natural.
- pron 11y agoMost languages with map/reduce don't have transducers (and they're certainly not central features). Also, don't forget that while Clojure is functional, it is also very much imperative (it's a functional-imperative language rather than a pure-functional language).
- dragonwriter 11y ago> Most languages with map/reduce don't have transducers That's true but mostly irrelevant to the point that transducer usage isn't complex once one understands map/reduce, which are common, whether or not transducers are.
- afandian 11y agoNo need. Getting started, and to a level where you can be productive, is very easy. LISP is a very simple language, and lots of the features of Clojure mean that it's simple in practice too. That's compared to Haskell and Scala, which do require a little theory in order to get started. IMHO. There will perhaps come a time, where you want to know about and transducers, but by that time the concepts won't seem intimidating.
- markc 11y agoActually the learning curve is very gentle, and you can gradually expand from basic features into the more advanced stuff when ready. Many of the Clojure features that have sophisticated underlying design principles (like transducers) can be used cookbook style from easy-to-understandable examples. Jump in, the water's warm.
- birdsbolt 11y agoThis is only slightly complicated if you're writing your own transducer operation. What is interesting is that these transducing operations can be written quite generically - code reuse is huge. But, usage of transducers is similar to Java 8 Streams, or Haskell stream fusion, only that the implementation is fully generic, not dependent on the container/source.
- astine 11y agoThat's not a very plain-language description of transducers. Transducers are functions which can be applied to any sort of collection or sequence. You can use then to do something like filter a collection or an input stream with the same code. They are basically just a way to make things like 'map' and 'filter' work on datatypes other than sequences, such as streams or channels. http://blog.cognitect.com/blog/2014/8/6/transducers-are-coming http://blog.cognitect.com/blog/2014/8/6/transducers-are-comi...
- susi22 11y agoAgain, that's not true. Transducers are about reducing things. That's why a transducer first needs a reducing function. But I won't go into details what trasnducers are. There is many good (and long) blog posts about it.
- astine 11y agoNo, reducers are about reducing things. Transducers are about creating reducers that can be used on arbitrary collection-like things. Reducers come from the observation that many higher order operations on collections can be built on reduce. You just supply the right reducing function and you get the equivalent to 'map' or 'filter'. This is useful because when you start chaining these higher order functions you can gain performance be replacing the multiple function calls with a single reducer based function. To take the example from the main docs: (fold + (filter even? (map inc [1 1 1 2]))) Here, each function returns a reducer which is a combination of the original collection ([1 1 1 2]) and a reducing function which will be applied to the collection. Ultimately this code will result in a single call to reduce with a single function applied to [1 1 1 2]. This differs from the 'standard' way of doing this: (reduce + (filter even? (map inc [1 1 1 2]))) ...in that no intermediary representations of the collection are necessary. Neat. A transducer takes the same idea, but does it in a way that lets you apply this to arbitrary collection-like things, not just seqs. A transducer works by cutting out the original collection; you build the reducing function by chaining transducers together and pass it later another function which will pick apart the collection-like thing. So: (into [] (r/filter even? (r/map inc [1 1 1 2]))) Becomes (into [] (comp (filter even?) (map inc)) [1 1 1 2]) Which is not exciting until you realize that that middle term can be passed to 'chan' al la: (chan 1 (comp (filter even?) (map inc))) Which means that everything going through that channel will increased by filtered with 'even?'. Now you have a suite of functions which will take a transducer and use it in a lot of different contexts allowing you use the same logic on streams, sequences, channels etc. This same logic, that you would originally have expressed with a series calls to 'map' 'filter' 'take' and applied only to a sequence.
- jarcane 11y agohonestly, I use Clojure 1.7 for work every day and I don't even know what a transducer is. It's easy to overstate the necessity of advanced features, ones very few programmers probably actually use.
- dj-wonk 11y agoTransducers are part of cultural drive of the Clojure community to identify common patterns and simplify design. Rich's presentations do a nice job of explaining how a transducer is about separating [how to do the work] from [where the work is done]. By "work" I mean mapping, filtering, reducing, and so on. By "where the work is done", I mean that a transducer doesn't care what kind of data structure it operates on. If you keep this in mind, perhaps re-reading http://clojure.org/transducers http://clojure.org/transducers won't be as intimidating. As a general comment, to those new to Clojure, when you find something in Clojure that seems strange or different, I encourage you to ask "What does [function X] care about? (e.g. need to know)" and "What does [function X] not need to know?". This relentless drive to simplify design and responsibilities mean that functions are small and "opinionated", but in ways that are driven by constraints, not arbitrary decisions. So these choices make a lot of sense -- I'd argue they flow pretty naturally.
- jarcane 11y agoDon't get me wrong; I'm not knocking it. I definitely see the value in these kinds of features. Like zippers, I'm sure it's another case of "If you understand it, it's really useful." The point is, you don't necessarily need it to get the job done, and you certainly don't need to be intimidated about it or feel obligated to learn it right off. Even Haskell isn't actually so difficult to grasp the basics of, if you keep this in mind and just think "Do IO in a 'do' block" and go about your way. See [1]. You don't have to know everything in any language just to get some work done, a lot of times advanced features are just that: advanced, stuff for doing things a bit more efficiently, or to handle certain rough edge cases. Learn them in their own time, and they'll make you better at what you do, but don't get wrapped up too much in expecting perfect efficiency from yourself. A lot of programmers seem to be, as a people, kinda bad at this kind of self-reflection, like we're all sheep in wolves' clothing trying to avoid showing a hint of weakness. I know I sure am. There's nothing wrong with not knowing something, just try and take a moment learn it when you can. [1] http://blog.jle.im/entry/io-monad-considered-harmful http://blog.jle.im/entry/io-monad-considered-harmful
- enoch_r 11y agoIf you have an understanding of functions like map, filter, and reduce, transducers are actually pretty easy. Say you have `(map inc [1 2])`. You can run that, and get `'(2 3)`. A transducer is the `(map inc)` part of that call (slightly confusingly, this isn't partial application or currying). You can apply it to something like `[1 2]`, but you can also compose with it, by combining it with say, `(filter even?)` to get something that represents the process of incrementing everything, then removing odd numbers. Or you can put in things that aren't collections, like asynchronous channels, and get back a new channel with the values modified accordingly. That's pretty much it. What I think I love most about Clojure is that there are fantastic, esoteric, academic ideas that, when I read about them in a context like this for the first time, I a) do not understand them, and b) have no idea how they would be useful. Then I read an example or two, and suddenly it's apparent that the tool is really as simple as it can be--there's very little accidental complexity--and is extremely useful.
- deleted 11y ago[deleted]
- aoeuasdf1 11y agoThe way you explain it, it's no different from functions and function composition; in which case, why invent new vocabulary? I do remember looking into them before and translating them into Haskell and they ended up not being identical to functions in the trivial sense that you suggest, but I forget how.
- arohner 11y agoWhy have new vocabulary for the state monad? Transducers are mostly function and function composition, but with a specific signature. There are a handful of contracts on a transducer, so it is useful to have a name, so you can say "this function takes a transducer" and "this function returns a transducer".
- kazinator 11y agoTransducers are functions. The thing is that they are functions that are designed to serve as the functional argument to reduce. And they pair with ordinary functions which are not transducers. For instance if we have (map inc [1 2]), there exists a transducer function T such that: (reduce T [1 2]) == (map inc [1 2]) I.e. we can somehow do "map inc" using reduce. Okay? Now, the clever thing is this: why don't we allow map to be called without the list argument? Just let it be called like this: (map inc) This looks like partial application, right? Now what would partial application do? It would curry the "inc", returning a function of one argument that takes a list, i.e.: ;; if it were partial application, then: ((map inc) [1 2]) ;; same as (map inc [1 2]) But Hickey did something clever; he overloaded functions like map so that (map inc) returns T! (reduce (map inc) [1 2]) ;; same as (map inc [1 2]) The cool thing is that this (map inc) composes with other functions of its kind. So you can compose together the transducers of list processing operations, which are then put into effect inside a single reduce, and the behavior is like the composition of the original list processors. It's like a linear operator; like LaPlace. Composition of entire list operations in the regular domain corresponds to composition of operations on individual elements in the "t-domain".
- brudgers 11y agoClojure is sophisticated [0] but it is hard boiled down to necessary complexity. This means that ordinary language features like interop [1] are well sugared and more abstract concepts like transducers are simple to implement and map well to their description [2]. Stuart Halloway's Programming Clojure captures this idea. [0] and big for practical purposes like Common Lisp. [1] you can get at all of Java perhaps better than you can from Java using the REPL. [2] like lexical scope and continuations in Scheme.
- spion 11y agoTransducers create functions that are meant to be passed to reduce (i.e. take accumulator and element and return a new accumulator). Its possible to implement most other functions (map, filter, take etc.) using reduce. Transducers take advantage of that. Unfortunately, if you try to do that, you'll notice that the implementation is sometimes tied with the way you build the entity: e.g. for vectors, map implemented in terms of reduce would start with an empty vector then append to it. That sucks. We want operation chains that are independent of the data structure they operate on. We want them to work on vectors, lists, channels, whatever - anything that can have a reduce-like operation (anything reducible) However, it turns out you don't necessarily have to recreate the entity (e.g. list) when chaining. All you need to know how to do is invoke the next operation in the chain, i.e. the next reduction function. For example: * map can apply the function on the element to get a new result, then call the next reduction function with the accumulator and that new result. * filter can check the element and either return the old accumulator or apply the next reduction function with the element, etc. Therefore, transducers simply take an additional argument: the next reduction function that should be applied. This lets you build up a chain of operations (e.g. map filter etc) that doesn't care about the kind of entity they're operating on. Only the last "step" must be a reduction function that needs to know how to build the result.
- phren0logy 11y agoYou may feel less intimidated by "Clojure for the Brave and True." The landing page features a rodent with an eye patch and a sword. http://www.braveclojure.com/ http://www.braveclojure.com/
- jsilence 11y ago> Delete ~/.emacs or ~/.emacs.d if they exist Ehhhh, no!
- KurtMueller 11y agoHence the emphasis on Clojure for the Brave.
- ZainRiz 11y agoDon't get disheartened. I just started this tutorial last weekend (and had no emacs experience before) and it's been great!
- yogthos 11y agoClojure is one of the easiest languages to learn. You need to know very few concepts to become productive in it. I get co-op students very 4 months at work and they generally start doing useful stuff within a week or so. I wrote a conceptual starter guide a little while back ( https://yogthos.github.io/ClojureDistilled.html https://yogthos.github.io/ClojureDistilled.html ), that covers all the basics that you need to know to get up and running.
- jgalt212 11y agoAre transducers necessary in Clojure because functions of function of functions (etc...) on immutable data structures execute slowly?
- harlanji 11y agoThey help relieve pressure on the garbage collector by eliminating intermediate sequence allocations (eg. (comp (map a) (map b) (filter c) (map d)) would create 4 sequences, transducers create none). Consequently you can work with results incrementally unless there is an intermediate flush required such as for a windowed aggregation. I imagine most applications aren't very sensitive to the performance gain, but it's good to know for when you need it. In addition it's a nice and testable, compos-able pattern. I've only done backend work, no cljs yet, but I'd call it reasonable practice to think in terms of compositions/transducers for most data transformation pipelines in the future though, throughout the stack, whether performance matters or not.
- tsmarsh 11y agoIts more like 18 months. Unless you already know a lisp or Haskell. The only thing I can say is that it is totally worth it, I know very few people who regret putting it in their head. The same is less true for Ruby, php, Visual Basic.
- nbardy 11y agoI had a similar feeling when I first starting using Clojure, but I found it was more of a discomfort from discussing programming language with a direct and accurate vocabulary. After a while I've become much more comfortable reading about and watching videos on programming languages in this style and I really enjoy being able to discuss and think about design decisions in a straightforward way.
- goldfeld 11y agoDive in! It's like beginning ballet over twenty: you'd really have to trust your slow, consistent, building momentum to eventually get you there. Learning Clojure up to getting remotely competent with it did take me a year and a half, during which I used it in all my projects. Also including getting into Emacs. I breathed it all throughout. Now I'm good in it, I have ease designing big FP systems, and I finally decided to learn transducers a few weeks ago and it took me me just an hour to grasp/implement it in my app. Neither a decade :)
- jwhitlark 11y agoBasic competence comes pretty quick, it's a small core language, compared to most. Most things like transducers you can ignore for a long time. The longest part of learning it for me was learning to think functionally, but you can do that in pieces, and nearly all of what you learn is applicable to any functional language, or even imperative languages with functional aspects.
- icey 11y agoIt would be great to see a refactor of some code using transducers to get a better sense of what they're useful for. From an abstraction standpoint, I can see the attraction; but I am having a tough time imagining how it would improve code in practice.
- birdsbolt 11y agoIt improves the performance by fusing some of the operations doing them in one pass instead of multiple passes, and it does so generically - operations are composed regardless of the source, and the implementation isn't looking at the type of the source at all. I believe one of the arguments was also that these couldn't be written in statically typed languages. Although, I do not know if this turned out to be true.
- coolsunglasses 11y ago>I believe one of the arguments was also that these couldn't be written in statically typed languages. Although, I do not know if this turned out to be true. It's not true, they were just abstrusely defined and there's some weirdness around the implicit effects that you can choose to either ignore or incorporate into the equivalent. Fusion is one of the main things Haskell is known for and an API that gets close enough to what one would use transducers for is `Control.Lens.Fold`. Others have made more faithful attempts at making it explicit, such as in this post: http://jspha.com/posts/typing-transducers/ http://jspha.com/posts/typing-transducers/
- puredanger 11y agoRe the last sentence, that is not true, nor was it a claim.
- birdsbolt 11y agoI think I saw a talk, or a statement somewhere, made by Rich Hickey - https://news.ycombinator.com/item?id=8342718 https://news.ycombinator.com/item?id=8342718 . I believe it was in this talk. Not that I was being negative about it.
- sharms 11y agoIf you want to build a website in Clojure, I highly recommend checking out http://luminusweb.net http://luminusweb.net - the documentation is amazing, and it incorporates nearly all of the best practices I have seen. Making an API in Clojure using Swagger gives you a full, interactive UI and documentation for your API, while also having a schema which makes sure you know what is submitted and that it validates (i.e. is that a string or a number?)
- yogthos 11y agoLuminus author here, thanks for the kind words. :) As a note making a Swagger app with Luminus is as simple as: lein new luminus myapp +swagger cd myapp lein run once the server starts, browse to http://localhost:3000/swagger-ui/index.html http://localhost:3000/swagger-ui/index.html to see your Swagger API
- akilism 11y agoNice I'm going to check this out... I've been using chestnut a lot lately. https://github.com/plexus/chestnut https://github.com/plexus/chestnut
- logicchains 11y agoI'm really impressed by how backwards compatible it is. I just changed the Clojure version from "1.6.0" to "1.7.0" for one of my side projects, without updating any library versions, ran it, all the tests passed, and it seems to work perfectly. It also didn't break my Emacs setup, which is a breath of fresh air compared to how much work it was to get the Haskell tooling working with the new 7.10 GHC release (GHC-mod for instance still doesn't have a compatible release, although the trunk mostly works with 7.10). Similarly, even though it's months after the 7.10 release there are still libraries that don't support it, like reactive-banana-wx, whilst a couple of the Clojure libraries I'm using haven't been updated in over a year yet still work fine on 1.7, and none of the libraries I'm using break on 1.7. To be fair, GHC and the Haskell ecosystem is far more complex than Clojure and its ecosystem/standard library. Nevertheless it's pleasant how easy Clojure was to upgrade (although of course this stability is nothing special: more conservative languages like Go and Java generally break almost nothing on upgrade).
- kul_ 11y agoYes this is something clojure users take for granted. I dont know the state of Scala right now but a year back even minor version bump was horrible in scala in terms of backward compatibility. Really impressive job by clojure code devs in terms of maintaining such stable releases.
- xixixao 11y agoIs the job simpler because Clojure is not statically typed?
- raspasov 11y agoOr because it's a lisp? : )
- arohner 11y agoI'm not a Scala user, but Clojure the language tends to be extremely stable. Existing stdlib functions almost never get updated, unless they add a new (backwards-compatible) arities. Releases tend to consist mostly of new features, and a small number of bugfixes.
- giancarlostoro 11y agoMy only negativity with Clojure isn't really with the language itself, but with the Debian / Ubuntu packages, they're way outdated. Not sure who ever maintained them, or why they stopped doing so 1.4 being the last version. Outside of that for anyone wanting to check it out, you could try downloading LightTable and using ClojureScript, seems to be close enough I am able to use Clojure books with ClojureScript, not sure entirely of it's differences or how backwards compatible one is meant to be with the other, though I suspect they're meant to be near identical aside from their available libraries maybe.
- diego 11y agoThe reason is that nobody (that I know, at least) uses them. The Clojure community uses leiningen, and leiningen takes care of fetching the version of Clojure a specific project needs. There is no point in installing one version of Clojure when the core is small enough that every project can have its own.
- ffreire 11y agoClojure is often billed as "just another JAR" and in my experience I've never felt the need to install via any package manager. My workflow often consists of a new leiningen project where I define the version of Clojure that I want to use for the current project, along with whatever I else I need for the task at hand. Likewise, if I just need a quick repl to test something out, I'll simply use `lein repl` and fire away.
- nerd_stuff 11y agoTo expand on this: If you're familiar with Python Leiningen takes the place of both pip and virtualenv. Every project has a project.clj file where you declare your project dependencies and running "lein deps" from your project root handles it from there. This includes libraries and the version of Clojure you're targeting. When you add/delete/change a dependency in project.clj you simply run "lein deps" again. You never have to run "pip freeze" or make a requirements.txt file because project.clj serves that purpose as well. As an example, Leiningen's own project.clj: https://github.com/technomancy/leiningen/blob/master/project.clj https://github.com/technomancy/leiningen/blob/master/project...
- pjmlp 11y agoWas the performance related work postponed?
- susi22 11y agoIf you mean the compilation fsync stuff: Yeah until 1.8
- pjmlp 11y agoI mean the compilation and startup time that people think lies on the JVM, CLR, Dalvik and ART when trying to run Clojure code.
- puredanger 11y agoIt sounds like you are referring to various ideas around delayed var loading to improve startup performance - most of that was delayed, although there was one change that improved compilation speed and improves the performance of some projects.
- pjmlp 11y agoYeah that was it, thanks.