37 karma · joined February 16, 2013
And the good programmer could do anything in a less eccentric language anyway, so...
In F# I would certainly call it "callTwice" too:
let callTwice aFunction y = aFunction (aFunction y) function callTwice(aFunction) {
return function(y) {
return aFunction(aFunction(y));
};
}
function square(x) { return x*x; }
var squareTwice = callTwice(square);
81 === squareTwice(3);When programming in a language you hate, don't take naming arguments for granted. It could be worse: you could be programming in Perl, where all arguments come in a flattened array.
Perl is the language with the highest occurrence of "subtle" and "ambiguous" in its documentation and tutorials that I have ever seen. Humans may be subtle and ambiguous, but programming languages should be clear and precise.
> If the goal of the competition is to slice apples
What?
Sure, it has been working fine for many years, and a die-hard fan of C++ would come up with many criticisms of anything new: No pointers? It's for beginners only. Garbage collection? I can see the programmers that created it are not very proficient. Etc. etc. etc.
And you know what? There are really great programming languages that do many things differently and also work very well, or even better than C++. They are not perfect, but the traditional way of doing things (C++ or the standard music notation) was not perfect either to begin with.
So, I hope people experiment more and more with new notations, and maybe they will improve the standard notation or even replace it someday.
Let's suppose map is defined as:
> let map (aList) (aFunction) = ...something here...
(this is according to https://github.com/raganwald/allong.es/blob/master/README.md which seems to have the parameters reversed when compared to F#'s Seq.map, Lis.map, etc.)
And let's suppose applyLast is defined as:
> let applyLast (aFunction) (anArgument) = (fun (x) -> aFunction (x) (anArgument))
So makeMapper is:
> let makeMapper = applyLast (map)
Read the above as: makeMapper is a function just like applyLast, but the first argument (to applyLast) is already provided, being "map". The functionality of applyFirst is implicit when the remanining parameters are missing, so we only need applyLast.
So makeMapper is called as
> let mapperWithAGetter = makeMapper (aGetter)
This completes the call to applyLast, so now we have a (fun (x) -> map (x) (aGetter))
Now we only need to bind x. The result is called like this
> mapperWithAGetter (aList)
IMO, all of this could've been written as:
> let makeMapper (aGetter) = fun (aList) -> map (aList) (aGetter)
Or:
> let makeMapper (aGetter) (aList) = map (aList) (aGetter)
Read both as: makeMapper takes aGetter and returns a function which takes aList
Notice that everything would be much easiear if map took aFunction as its first parameter:
> let map (aFunction) (aList) = ...
> let makeMapper = map // duh
Remember that partial application is implicit!
It would also be easier if applyLast had better syntax, using _ for the missing parameter (the first), as in this Scala-like snippet:
> def makeMapper(aGetter: Any => Any): List[Any] => List[Any] = { _.map(aGetter) }
(I guess Haskell has some nice syntax for this too, but I don't think F# has anything like this)
All of this was not easy to get right, I hope I didn't make any mistake regarding the position and number of parameters.
totals = [order.total for order in orders]
(like some other poster in this thread did)
Then you don't even need to know what "map" means, you only need to know "for" (well, maybe you would need an insight that "order" is defined after its use, but I digress)
More than once I have found about a new technique in language A and thought: "Wow, this is clever". Then sometime later I learnt language B where that technique is not only common place, but has some nice syntax sugar and is used throughout the whole standard library. And that makes a huge difference in the perceived cleverness of the code.
I also learned how data structure libraries can be separated from user code (when learning C in class we usually created ad-hoc data structures heavily coupled with the calling code).
Then you have to take into account a few other criteria, such as [1] internal coherence in the language, [2] difficulty in implementation (and explaining to others) [3] what your target audience is, and what they want, [4] what competitors are doing.
I think full operator overloading would hurt [2], but special-casing Bignums would not hurt [1], [2] at all (as I said, JSP EL already have +,-,*,/, etc. , String already have +, +=).
[3] This is what this thread is all about, no need to repeat :-D
And [4]... Well in this case Java is really playing catch up.
Now I do program in Java 5/6 and it would be really sad if the language was still stuck in the 1.4 days.
Damn, so why are they encouraged in Java? 11 out of 10 frameworks insist that you write getters/setters so properties can be accessed from outside.
Java designers need to get more practical. If getters/setters are unavoidable, I'd better have them without so much boilerplate in my code.
No need to go the C# way. Just enough to avoid repeating the name and type 3+ times each would be great.
It's already going to get lambdas. Add some shortcuts for getters and setters (Lombok-style, maybe) and collections literals, then you get surprisingly close to Groovy (and JPA @Entity classes will become 1/6 of their sizes). And just like Strings have special + and +=, Bignums could have some compiler help (as they already do in JSP EL).
It will still be behind C#, but not by much. At that point I could agree that Java and C# have different philosophies and Java will never get true operator overloading, but it doesn't matter much if the most important use cases are covered.
Some people seem to think that if they don't use, then it doesn't matter. In many business applications, you don't even need floating point (you just transfer data to the database and back), anyway.
Are floats and doubles "little features"?
In computer graphics, you need lots of floating point calculations. Are ints and longs "little features"?
In embedded software, you usually don't want to use resizable strings (C doesn't even have this feature built-in), because reallocations are expensive or unavailable. Are resizable strings (or containers) "little features"?
Different programs have different needs. If you haven't stumbled upon a good use case, doesn't mean that it's useless.
OTOH, sometimes we need a "panic"(¹) function, and a main loop that catches everything and either communicates the error to the user, or restarts the whole thing. That's why unchecked exceptions can be useful too, especially since they makes it harder to ignore errors - who has the patience required to check every return value of printf in C?
(¹) No, I've never programmed in Go.
I guess their brains simply deadlock.