Naming and Body Language in Functional Code 41
I wrote a blog the other day about functional refactoring and I had what I thought was a good example:
absPosition :: Buffer -> Int
absPosition (Buffer (x, y) contents) = x + lenPreviousLines contents
where lenPreviousLines =
foldr ((+).length) 0 . take y . terminatedLines
Almost immediately, I saw replies on a couple of forums (including this one) which pointed out that I could’ve written the code this way:
absPosition (Buffer (x, y) contents) = x + lenPreviousLines contents
where lenPreviousLines =
sum . map length . take y . terminatedLines
It’s funny, I thought of using sum
instead of foldr
back when I was using Haskell’s line function. The code I had looked like this:
absPosition (Buffer (x, y) contents) = x + lenPreviousLines contents
where lenPreviousLines =
foldr ((+).((+1).length)) 0 . take y . lines
But, I realized that the code wasn’t in great shape for sum
, so I created terminatedLines
, used it and promptly forgot to do the refactoring I set out to do.
terminatedLines :: String -> [String]
terminatedLines = map (++ "\n") . lines
From an imperative point of view, terminatedLines
looks a bit silly: What?? You’re going to append a newline to each line in a list of lines you just created just so that you can count it?? But, I suspect that it isn’t that bad. The evaluator pulls values from each line and as it reaches the end of one it should just put a newline at the end of it. If I’m wrong about this, please let me know.
In any case, I agree that the code looks better with sum
that it does with foldr (+) 0
. The big question is – should we refactor any more?
Someone with the handle sterl suggested a very cool trick. I could drop the where clause like this:
absPosition (Buffer (x, y) contents) =
x + (sum . map length . take y . terminatedLines) contents
And then move on to this:
absPosition (Buffer (x, y) contents) =
sum . (x:) . map length . take y . terminatedLines $ contents
What’s going on here? Well as sterl put it, we’re summing anyway so why not prepend the x
onto the list that we are already summing?
Part of me likes this and part of me doesn’t. One the one hand, it’s brief, but on the other hand, the code isn’t telling us why it is doing what it is doing anymore. In the original code, there is an algorithm:
To get the absolute position, add the x position of the location to the sum of the lengths of all of the previous lines.
In the new code, the algorithm is:
To get the absolute position, sum the current x position with the lengths of all of the previous lines.
Wait, that’s sort of the same, isn’t it?
This example points to a fundamental dilemma that I have with naming in Haskell. I’m used to introducing names in lower-level languages to bridge the gap between intention and mechanism, but what happens when your mechanism is so high-level that it can speak for itself? Maybe we don’t need names as much?
Now, I know as I write this that someone is going to look at this as an extreme statement. It isn’t. Names are useful, and indispensable, but really they are only one of several ways of communicating meaning. In each case, we have to pick the right tool for the job. With Haskell, I think that programmers communicate with structure as much as they communicate with names. It’s the body-language of their code.
I very much agree. Significant Names become a problem when the point of the code is to communicate the naked structure. In that case, single letter names emphasize the ‘wiring pattern’ that is the actual content.
How about x + (length . unlines . take y $ contents)?
josh: You mean: x + (length . unlines . take y . lines) contents
I’ll have to try that out.
If your code is sufficiently abstract to properly capture domain concepts, its naming conventions should be the naming convention of the domainn it models (e.g. statistics, cryptography, finance ..).
Same rules for good DSLs and EDSLs apply here.
I like:
Also, if you define:
then you can do:
How about:
sum . zipWith ($) (replicate y length ++ [const x]) $ terminatedLines contents
Or, “take the sum of the length of the first y lines, and x for the line after that.”
Jake: That’s wild. Is that a section of function composition?
lilac: I’m going to have to work on understanding that one.
Yes.
(. lines)
takes a functionf
and createsf . lines
. That is then applied to(unlines .)
, which results in this:I normally avoid sections with function composition, but I think it is visually meaningful in this kind of simple case.
Correction to the above:
(unlines .)
is then applied to that, which results in this [...]It might be clearer to rewrite my suggestion as:
About this game of rephrasing haskell programs into mysterious expressions involving hordes of composition operators and other higher-level combinators being applied to eachother, with few meaningful identifier names:
For higher mathematics, maybe there are real advantages in the use of abstracted language and definitions. Maybe the abstractions used really elevate you to a higher level of discourse, where you can work in peace and clarity free of the irrelevant details. Perhaps this is also true for well-designed DSLs in a language like haskell.
But for simple bits of programming, taking this kind of thing to the extreme seems counter-productive. It doesn’t raise you cleanly to a higher level of abstracted discourse, it just adds indirection to a simple idea, requiring a lot of mental energy to unpack the definition of something which is trivial.
Matthew: I agree. The question seems to be where do you stop? I suspect a lot of it has to do with what you assume about your audience.. whether some idioms common enough to avoid head-scratching.
Matthew: I think my version is a good example of the goal of this whole exercise, though. I have expressed the whole idea of “take y lines, get the length of that, then add x to that” rather clearly, I think. Far more clearly than the original, certainly.
@Matthew: You don’t understand functional programming, so of course this looks very foreign to you. And, by understand, I truly mean eat, breath, sleep, and think in it. You’re an OO coder, and it shows, just by your comment.
@Michael: Matthew’s point is valid, but what I think you’re going through is the classic “newbie” phase of functional programming. You know just enough to be dangerous—that is, you can speak the language, but you’re not fluent in it like a native coder/speaker would be. As you indicate, much of functional coding is body language
The funny thing is, Lisp and Forth coders have been trying to tell people this FOR DECADES. The real question is, why hasn’t anyone been listening?
@Matthew: Taking anything to extremes is liable to be more trouble than it’s worth, but these examples are hardly extreme. As for “unpacking the definition”, using function composition and eschewing names for intermediate parts often simplifies the reading because there is less to unpack. In the C/Java/Perl world I often have to run around in circles reading function after function before finally getting to the real code; in Haskell things are usually a lot more direct.
(++) might be space equivalent, but I think it’s not time equivalent:
Actually, terminatedLines isn’t a good idea, because (++) is slow (Rule of thumb: Putting things in front of a list is good, appending things at the end is bad, because in the latter case you first have to traverse the whole list).
For the example in question, I’d just use a list comprehension:
No need to make code harder to read than necessary.
Mark: Thx.
Dirk: I was hoping that with lazy evaluation, the reduction order for something like [1,2,3] + [4,5,6] would be 1:(2:([3]+[4,5,6])). In other words, we consume elements from the head and then the append happens sort of as a cons and at end of the consumption. from the definition of (++) it looks like that is what happens.
Michael Feathers,
re: Dirk: terminatedLines isn’t a good idea
While [1,2,3] + [4,5,6] indeed reduces to 1:(2:([3]+[4,5,6])), the cost of that reduction is the length of the first list. In the context of your map (++”\n”) code, it’s decidedly non-trivial. That’s Dirk’s point.
In other words, append doesn’t do automagical, never mind zero-cost, consing “at the end of the consumption.” That said, you might want to check out difference lists.
When to extract and not to is a good question. I tend to only give names and extract when there’s some redundancy to be exploited. Otherwise, it always makes sense to me to inline—proper formatting and occasional comments are enough otherwise. Nice Haskell can read very fluently already, I think.
Viewing the simple stuff inline can also expose all sorts of other nice optimizations such as why “terminatedLines” can be replaced with, e.g., Jake’s very elegant code above.
“editor combinators” and variants such as the above are really nice ways to denoise your code—abstracting out views on data, so to speak, rather than operations on it.
I personally love the terseness of functional programming for a very good reason: It breaks the ungodly, pretentious habit programmers have of “nice-naming” – that is, naming functions and procedures with names that suggest what the function is meant to do, but doesn’t.
I suppose the reason the practice gets on my nerves so much is because I tend to run into the mid-level-skill types – the people who think they’re much cleverer than they are. There’s nothing that makes a team member want to step back and watch a drowning man go under, than hearing, “Jeez, can’t you read?!? It’s OBVIOUS what my program does! It’s called ‘addStudentToTutors’!” It’s obvious what the program is supposed to do, yes…
One of the nice thing about doing all of those Flying Wallendas-style functions, is that it breaks your functions up into dense nuggets of power, that you are then “compelled” to comment. It’s never bad to just throw a line of commentary that says: ”—‘withLines’ takes a function, and makes a new function that applies ‘lines’ to its argument, runs your function on that, and then does ‘unlines’ to the result”.
Functional programming in general, gives you the idea that you’re describing what you want to happen, instead of what you have to set up to get it to happen.
i have read it
Apple’s launch of the iPhone 4 white has seen the greatest excitement for a new phone ever, with HD video recording, a super high-res screen and ridiculously slim dimensions, it’s not hard to see why its so popular in the world.
With the right tool, you can easily burn mp4 to dvd and itunes to dvd. Also, you can use drm removal tool to remove drm protection from itunes, zune, amazon legally. wmv to dvd, mov to dvd, mp4 to dvd, itunes to dvd
I suppose the reason the practice gets on my nerves so much is because I tend to run into the mid-level-skill types – the people who think they’re much cleverer than they are. There’s nothing that makes a team member want to step back and watch a drowning man go under, than hearing, “Jeez, can’t you read?!? It’s OBVIOUS what my program does! It’s called ‘addStudentToTutors’!” It’s obvious what the program is supposed to do, yes…accounting services
I think that programmers communicate with structure as much as they communicate with names. It’s the body-language of their code.
As a matter of truth, you will find some factors for individuals to decide the value of the rolex watches. In order to get precious rolexes watches for collecting, you’ll want to pay attention to the following aspects. At 1st, you need to judge the amount of the fake rolex. The amount of the Rolex DateJust watches existing in rolex watches the world is crucial. If Rolex Daytona is exclusive, and it has a small amount within the world, Swiss Replica Watch is going to become far more useful replica watches with the development of years. A widespread Discount Watches just isn’t worth to collect. Useful Rolex Day Date are available in tiny amounts. The distinct looks of these designer fake watches are extremely unique. In most models, the face dials generally feature a layered design. This makes the brand genuinely intriguing and attractive. The cheap watches are created from a few of the finest supplies utilized in contemporary Breitling Watches generating. Copy Watches supplies incorporate solid Fake Watches state and refined stainless steel, diamonds, reinforced crystals and other precious stones. In some models, the bracelets consist of a mixture of gold and stainless steel while a much more casual leather band is also available. The Omega Watches of Raymond Weil are mysterious and intriguing on account of the special textured layering of the front faces. Do not buy sport Cartier Watches if you are an office lady. The replica watches are an individual belonging that represents the taste and the style of a person. Imitation Watches will be easy for you if you have already known about yourself well. At last, we bet you can find the ideal women’s replica watches uk for the women in your life as long as you do research correctly.
This article is very usefull for me! I can see that you are putting a lots of efforts into your blog. I will keep watching in your blog, thanks.
KEESTRACK?manufacturing expert of mobile crusher and mobile screening equipment. Company engaged in the research & development, manufacture, sales of track screening machine,mobile screening,cone crusher,jaw crusher,impact crusher,mobile screening equipment,mobile crushing equipment, till now we are proud to say we are at front of the industry.
Any lady with wholesale beads wedding on the brain will be dropping not so faint hints beside the wholesale jewelry beads,wholesale beads way so pay consideration when you’re receiving prepared to pop wholesale pandora beads the query. You can also seem at the jewelry she already owns to get an clue of her chic, especially regarding what type of wholesale fashion jewelry metal she loves. Keep in mind that she will be got up in this ring for the rest of her life so make definite to choose something that suits her personality.
Any lady with wholesale beads wedding on the brain will be dropping not so faint hints beside the wholesale jewelry beads,wholesale beads way so pay consideration when you’re receiving prepared to pop wholesale pandora beads the query. You can also seem at the jewelry she already owns to get an clue of her chic, especially regarding what type of wholesale fashion jewelry metal she loves. Keep in mind that she will be got up in this ring for the rest of her life so make definite to choose something that suits her personality.
useful code. Thanks.
internette görüntülü olarak okey oyunu oyna, gerçek kisilerle tanis, turnuva heyecanini yasa.
.However be cautious, coach poppy handbags are accessible in finest covering which replica makers acclimate to a little admeasurement but they are never fabricated in plastic; watch out, artificial pieces may be absolute affected pieces. Today the appearance trend is new but back the morrow comes, you see article new. Wherever possible, coach hobos handbags with 18-carat coach and amuse yourself that whether they alive up to the brilliant affection the austere coach satchelsangle for.
I really enjoy your articles. Very well written. New fashion women Guess Purses for wholesale on line from China free shipping
A buffer is a better way. Anyway. A good method to backup files on iPhone for you.
This article is GREAT it can be EXCELLENT JOB and what a great tool!
Australia Beats By Dre Studio dr dre beats headphones beats studio beats pro beats solo hd pro headphones music Official store Monster Beats By Dre Pro
An informative post… Code written on a single line with the function name is difficult to read… Besides, most of your functions will consist of many lines of code… Microsoft Support
If you are in search of nice Dr Dre Beats,our online store will be your first choice. Welcome. The Dr Dre Beats Studio is purchased by a lot of people due to its superior quality and low price. Start your shopping now! The Dr Dre Beats Tour Black is taking a large market now, so buy one at once. We accept paypal. Everybody like this world famous brand Dr Dre Beats Pro because of its finest quality but cheap price. You can order one too. Buy it quickly. More surprise are waiting for you if you order our AAA quality and cheaper price Dr Dre Beats Solo HD. Never lose this opportunity. We can supply you this most people loved Dr Dre Beats In Ear with fast delivery and free shipping. Why don’t you seize this precise chance to change your style by buying our latest Beats Studio Sale. Move your finger to log in. How can you stand still when seeing so attractive Dr Dre Beats Limited? Won’t your heart beat more fast after seeing our eyecatching Dr Dre Beats Sale Online? What are you considering? Rush to purchase!!!!We are waiting for your coming!! Beats Dr Dre are worthy owning. Well-known Dr Dre Beats Studio Black Yellow have the heights range from around the ankle to above the knee, and they are available in different colours. This Beats By Dr Dre .
Naming and Body Language in Functional Code 39 good post12
Naming and Body Language in Functional Code 40 hoo,good article!!I like the post!166