That's right - idiomatic functional programming is very declarative (from what I gather). Thanks for the references, and yes, I had recognised the motivation that ;).
You ask "Is the distinction between intention and implementation considered unimportant, or not so important in functional programming?" and I think the answer (at least my answer) is no, not at all, not in anyway, absolutely not :). The difference is that intention is often hidden behind a whole bunch of incidental complexity that Clojure (due to its higher level abstractions) just doesn't seem to have. When you have 40 lines of code to filter something, sort it and then transform the results, the message of what it is trying to achieve gets lost. When that same implementation is as elegant as "(->> col (filter my-pred) (sort-by :my-key) (map #(...)) then the HOW is right there. At worst you might have (defn do-it [col] (letfn [(interesting? [x] ....) (sort-criteria [x] ...) (transformer [x] ....)] (-> col (filter interesting?) (sort-by sort-criteria) (map transformer))) or (defn- interesting? [x]...) (defn- sort-criteria? [x]...) (defn- transformer [x]...) (defn do-it [col] (-> col (filter interesting?) (sort-by sort-criteria) (map transformer)) The reason that "do-it" exists and is the right thing to do (i.e. the WHAT or the WHY)? Again, in Clojure, I don't know why (other than the reasons already given) but it is much easier to group related things together, so the domain those things are working in, the implicit objective of the cohesive group of function is transparent. In Java, if you stick to small classes then you tend to end up with a whole bunch of classes whose inter-relationship isn't particularly clear. Package names help but then you end up with very deep hierarchies. In Clojure, because of the brevity it feels less icky to have ns's with many more defs than the number of methods you would expect in a class, or indeed the number of classes in a package. It isn't unusual to find sub-groups within a ns, typically demarcated by a string of semi-colons: (ns ....) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; - some logical group (defn- ..) (defn- ..) (defn ..) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; - some other logically cohesive group (defn- ..) (defn- ..) (defn ..) In summary, as David and I have said - good design is good design, the characteristics of which cross OO and FP (even things like immutability being good). The barriers to achieving that good design are local to every paradigm and then every implementation language. For me, Clojure opened my eyes to exactly how many "best practices" (particularly design patterns) were addressing incidental complexity. I dunno - it is all subjective and I am still working this out in my head (turns out a year isn't quite enough to kill decades of viewing the world through OO thinking ;)). I frequently cringe when I look at Clojure code I wrote a month ago. I am not sure the process of "yeah, that is good, <wait some period of time>, wow, that is terrible, let me replace those 10 lines with a call to a few core APIs" will ever end, and nor should it. As Dr Eli Goldratt said, "Never say I know" (https://www.toc-goldratt.com/tocweekly/2011/06/never-say-i-know-eli-goldratts-latest-development/). On 13 December 2014 at 08:43, Philip Schwarz <philip.johann.schw...@googlemail.com> wrote: > Hi Colin, > >> there is much less naming-of-concepts. Clojure code tends to be much more >> about the shape of transformations than the semantics of those >> transformations. > > > yes, it seems to me that often (always maybe?) functional code speaks a lot > about HOW, and not much about WHAT > >> A case in point, you wrote [code](defn put-one-on-top-of-the-other >> [top-half-of-diamond bottom-half-of-diamond] (concat top-half-of-diamond >> bottom-half-of-diamond))[/code]. I think most people would inline that. >> Extracting it however, give helpful information about the structure which >> isn't captured by the call to concat, namely the vertical nature >> (top/bottom). Of course, if the variable names were retained then is also >> sufficient but they almost certainly wouldn't be. > > > Yes, that method was introduced by an application of the Explaining Message > pattern. > > Here is how Kent Beck describes the pattern in Implementation Patterns: >> >> The first example I saw of this was in Smalltalk. Transliterated [into >> Java], the method that caught my eye was this: >> >> Explaining Message >> The distinction between intention and implementation has always been >> important in software development. It is what allows you to understand a >> computation first in essence and later, if necessary, in detail. You can use >> messages to make this distinction by sending a message named after the >> problem you are solving which in turn sends a message named after how the >> problem is to be solved. >> >> highlight(Rectangle area) { >> reverse(area); >> } >> I thought, “Why is this useful? Why not just call reverse() directly >> instead of calling the intermediate highlight() method?” After some thought, >> though, I realized that while highlight() didn’t have a computational >> purpose, it did serve to communicate an intention. Calling code could be >> written in terms of what problem they were trying to solve, namely >> highlighting an area of the screen. >> Consider introducing an explaining message when you are tempted to comment >> a single line of code. When I see: >> flags|= LOADED_BIT; // Set the loaded bit >> I would rather read: >> setLoadedFlag(); >> Even though the implementation of setLoadedFlag() is trivial. The one-line >> method is there to communicate. >> void setLoadedFlag() { >> flags|= LOADED_BIT; >> } >> Sometimes the helper methods invoked by explaining messages become >> valuable points for further extension. It’s nice to get lucky when you can. >> However, my main purpose in invoking an explaining message is to communicate >> my intention more clearly. > > > And here is a summary of how Beck originally described the pattern in > Smalltalk Best Practice Patterns: > > How do you communicate your intent when the implementation is simple? > Probably the most frustrating part of learning Smalltalk > You see a message like highlight and think: this has to be something > interesting > > ParagraphEditor>>highlight:aRectangle > > self reverse:aRectangle > > What is going on? Communication. Most importantly, one line methods are > there to communicate. > Explaining Messages are the most extreme case of writing for readers instead > of the computer > How do you communicate your intent when the implementation is simple? > Send a message to “self”. Name the message so that it communicates what is > to be done rather than how it is to be done. Code a simple method for the > message. > Three examples: > > > Collection>>isEmpty > > ^self size = 0 > > > Number>>reciprocal > > ^1 / self > > > Object>>=anObject > > ^self == anObject > > > > My program constructs the diamond by putting the top half of the diamond on > top of the bottom half. The implementation is simple: the top and bottom > parts are sequences that just need to be concatenated. But the > implementation is a detail, and may even change one day, so I encapsulate it > behind Explaining Message put-one-on-top-of-the-other. > > Explaining Message allows us to separate intention (the WHAT) from > implementation (the HOW): the method name tells us WHAT, and the method body > tell us HOW. > > Is the distinction between intention and implementation considered > unimportant, or not so important in functional programming? > > Philip > > On Saturday, 6 December 2014 18:40:16 UTC, Colin Yates wrote: >> >> Excellent question and I will be watching this thread with interest. >> >> Similar to David Della Costa, I find a bit difference between Clojure and >> Java for example is that there is much less naming-of-concepts. Clojure code >> tends to be much more about the shape of transformations than the semantics >> of those transformations. >> >> A case in point, you wrote [code](defn put-one-on-top-of-the-other >> [top-half-of-diamond bottom-half-of-diamond] (concat top-half-of-diamond >> bottom-half-of-diamond))[/code]. I think most people would inline that. >> Extracting it however, give helpful information about the structure which >> isn't captured by the call to concat, namely the vertical nature >> (top/bottom). Of course, if the variable names were retained then is also >> sufficient but they almost certainly wouldn't be. >> >> I am on the fence, and fall down frequently either side (you wouldn't >> believe the chaffing :)) - the more Clojure I write the more comfortable I >> am with dense calls to core.clj functions. But I also feel the loss of the >> info captured in variable names/function names as well. >> >> Another point worth mentioning is that the more Clojure you write the more >> you start to realise that the same "shapes" of functions come up time and >> time again - the structural shape of the code imparts knowledge sometimes. >> >> As David says, if you haven't looked at Prismatic Schema then have a look. >> I find the definition of the schema is also an excellent place to capture >> this extra layer of info in the names of those structures. >> >> Good question. >> >> On Saturday, 6 December 2014 10:48:02 UTC, Philip Schwarz wrote: >>> >>> Hello, >>> >>> can you please review my first solution to the diamond kata [1] and tear >>> it to bits: let me know all the ways in which YOU would improve the code. >>> >>> I am not so interested in a better algorithm for solving the kata. I am >>> learning Clojure and what I want to know is what YOU would do to make the >>> code more readable/understandable/maintainable, or just to make it follow >>> Clojure idioms and/or conventions that YOU find effective, or to follow a >>> coding style that YOU find more effective. >>> >>> Thanks, >>> >>> Philip >>> >>> [1] https://github.com/philipschwarz/diamond-problem-in-clojure > > -- > You received this message because you are subscribed to the Google > Groups "Clojure" group. > To post to this group, send email to clojure@googlegroups.com > Note that posts from new members are moderated - please be patient with your > first post. > To unsubscribe from this group, send email to > clojure+unsubscr...@googlegroups.com > For more options, visit this group at > http://groups.google.com/group/clojure?hl=en > --- > You received this message because you are subscribed to a topic in the > Google Groups "Clojure" group. > To unsubscribe from this topic, visit > https://groups.google.com/d/topic/clojure/zR5Ny7aoBM0/unsubscribe. > To unsubscribe from this group and all its topics, send an email to > clojure+unsubscr...@googlegroups.com. > For more options, visit https://groups.google.com/d/optout. -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.