Here are some situations in which currying does the trick: * You want to define a function which takes several arguments, but your programming language allows only one arg per function. * You have a function which takes several arguments, but you need to supply a function which takes fewer args. * You want to supply default values for some of a function's args. * You have a function whose default argument values don't suit you.
A Python Tkinter GUI callback can be "any Python function that takes no arguments" (http://docs.python.org/lib/node698.html). The question becomes what to do if you want to use an argument-taking function for your callback. You need to somehow feed the args to the function now without actually calling the function now, then pass the function itself with its fixed args to the Tkinter widget so that it can be called by the GUI later. Currying to the rescue.
Let's ignore Tkinter for a moment and just illustrate currying itself. First, we'll define a utility function to do the currying:
() {'dx': 10, 'dy': 10} gray box from (0,0) to (10,10) ('orange',) {'dx': 10, 'dy': 10} orange box from (0,0) to (10,10) () {'y': 100, 'x': 200, 'dx': 10, 'dy': 10} gray box from (200,100) to (210,110) () {'y': 520, 'x': 835} () {'color': 'red', 'y': 520, 'x': 835} () {'color': 'red', 'y': 520, 'x': 835, 'dx': 10, 'dy': 10} red box from (835,520) to (845,530) ('green', 262, 134, 500, 500) {} green box from (262,134) to (762,634)
The Tkinter function for creating a button can be called as follows: Button(master, text='foo', command=callback). We would like a button callback to simulate the drawing of a large, green, centered box using our box function: Button(frame, text='Draw Box', command=curried(box, 'green', (1024-500)//2, (768-500)//2, 500, 500))
Thanks for the more realistic examples. They give me a feel for "Currying" and I can imagine cases where it's useful. I'm still not sure it's all that big a deal, in Java there are usually multiple constuctors or call signatures filling in default values, and nobody blogs on how that's all powerful, but whatever. :-)
Currying is not for filling default values. // takes a size and an int // and pads the int with left 0's to fill the size // returns the string def pad(size: Int)(i: Int) : String = ... // obvious def pair[A](x: A) = (x,x) // hours list (as options for <select />) def hours = (0 to 23) map (pad(2)_ andThen pair)
If I hadn't currying for the pad function I should have written .. map ({ x: Int => pad(2,x)} andThen pair) // or something that will traverse the list 2 times map (pad(2,_)) map (pair)
I wish that the '_' will disappear somehow in scala, making methods all curried by default . So currying is useful when used with higher order functions, composition (or other combinators).
> Ramzi, you can avoid the _ if you use functions instead of > methods. I've posted a more complete discussion of the > sales tax example, complete with code that sidesteps the _ > issue, at > http://joelneely.wordpress.com/2008/03/22/currying-without- > lab-rats/ .
Right, but what I expect today from a language like Scala is to sweep out these subtleties (the least surprise rule). It's tiresome to have things that work in some contexts and not in others. I'm not a language designer, but why there's a difference between functions and methods? Especially when we're allowed to assign methods to functions.
> This is a big deal in languages like Haskell which only allow a single parameter, but Scala doesn’t have this restriction...
You make it sound like Haskell is deficient in that respect.
The fact is, Haskell and OCaml are extremely powerful precisely because their functions accept single parameters and integrate currying at an extremely basic level.
In Scala, currying seems like an afterthought. I'm not saying that's bad, but it make its use less natural.
> Thanks for the more realistic examples. They give me a > feel for "Currying" and I can imagine cases where it's > useful. I'm still not sure it's all that big a deal, in > Java there are usually multiple constuctors or call > signatures filling in default values, and nobody blogs on > how that's all powerful, but whatever. :-)
Currying can be very powerful. If you get a chance, take a look at a Haskell or OCaml tutorial. Currying can make it easy to compose functions in ways that tend to force the use of quite a few classes when you don't have it as a feature.
> Thanks for the more realistic examples. They give me a > feel for "Currying" and I can imagine cases where it's > useful. I'm still not sure it's all that big a deal, in > Java there are usually multiple constuctors or call > signatures filling in default values, and nobody blogs on > how that's all powerful, but whatever. :-)
I'm not functional expert but I think to truly understand the value of function currying you have to have a little experience in functional programming.
I think a better OO analog to this over 'class is to subclass' is an immutable Object implementing an interface which is constructed with any number of parameters and then passed to a method for it's methods to be called.
The best example of this I can think of off the top of my head is the way DataSources are used. A class that works with numerous database connections will take a DataSource instance as a parameter. Basically this interface provides one important method: getConnection(). But in order to fulfill this contract, the DataSource instance may need a number of parameters of its own and may even need to call on other Objects. The ability to construct this instance with an arbitrary number of dependencies without affecting the way that client code interacts with the DataSource solves basically the same kind of problem. Currying makes functions a little more like objects, IMO.
A big difference is that function currying tends to be a lot less verbose to what you need to do to produce the same kind of behavior in something like Java. That is, it tends to be used more because it is more convenient to do so. I say this is a good thing because this type of approach tends to produce more reusable code than procedural approaches.
> > Thanks for the more realistic examples. They give me a > > feel for "Currying" and I can imagine cases where it's > > useful. I'm still not sure it's all that big a deal, > in > > Java there are usually multiple constuctors or call > > signatures filling in default values, and nobody blogs > on > > how that's all powerful, but whatever. :-) > > I'm not functional expert but I think to truly understand > the value of function currying you have to have a little > experience in functional programming. > > I think a better OO analog to this over 'class is to > subclass' is an immutable Object implementing an interface > which is constructed with any number of parameters and > then passed to a method for it's methods to be called. > > The best example of this I can think of off the top of my > head is the way DataSources are used. A class that works > with numerous database connections will take a DataSource > instance as a parameter. Basically this interface > provides one important method: getConnection(). But in > order to fulfill this contract, the DataSource instance > may need a number of parameters of its own and may even > need to call on other Objects. The ability to construct > this instance with an arbitrary number of dependencies > without affecting the way that client code interacts with > the DataSource solves basically the same kind of problem. > Currying makes functions a little more like objects, > , IMO. > > A big difference is that function currying tends to be a > lot less verbose to what you need to do to produce the > same kind of behavior in something like Java. That is, it > tends to be used more because it is more convenient to do > so. I say this is a good thing because this type of > approach tends to produce more reusable code than > procedural approaches. I don't see subclassing as an analogy for currying it's more about morphing an object into another by fixing some of it's state. In the case of functions (which are objects in scala) "fixing some of the state" is applying the function to a number of expected parameters, and functions morph into other functions of lesser order. The power comes from the fact that from the same code you create different interfaces in the following example I create from the simple code a < b 3 kind of predicates Granted this code is really ugly, but that's what we can achieve by writing the 4 lines of scala code // scala def lessThan = (a:Int) => (b:Int) => a < b def flip[a,b,c](f :a => b => c) : b => a => c = (y) =>(x) =>f(x)(y) println(List(4,0,3) filter (lessThan(2))) println(List(4,0,3) filter (flip(lessThan)(2)))
import java.util.*;
publicclass Predicates{
publicstaticinterface Pred0{
boolean eval();
}
publicstaticabstractclass Pred1<T>{
publicabstractboolean eval(T t);
public Pred0 toPred0(final T t){
returnnew Pred0(){
publicboolean eval(){ return Pred1.this.eval(t);}
};
}
}
publicstaticabstractclass Pred2<T,U>{
publicabstractboolean eval(T t,U u);
public Pred1<U> toPred1_1(final T t){
returnnew Pred1<U>(){
publicboolean eval(U u){
return Pred2.this.eval(t,u);
}
};
}
public Pred1<T> toPred1_2(final U u){
returnnew Pred1<T>(){
publicboolean eval(T t){
return Pred2.this.eval(t,u);
}
};
}
}
publicstatic <T> Collection<T> filter(Collection<T> col,Pred1<T> pred){
LinkedList<T> list = new LinkedList<T>();
for(T item : col ){
if(pred.eval(item)) list.add(item);
}
return list;
}
publicstaticvoid main(String[]args){
Pred2<Integer,Integer> lessThan = new Pred2<Integer,Integer>(){
publicboolean eval(Integer a, Integer b){ return a < b ; }
};
Collection<Integer> col = new LinkedList<Integer>(){{ add(4); add(0); add(3); }};
System.out.println(filter(col,lessThan.toPred1_1(2)));
System.out.println(filter(col,lessThan.toPred1_2(2)));
}
if(lessThan.toPred1_1(3).toPred0(4).eval()){
System.out.println("yes 3 is less than 4");
}
}
I realize it's a bit of apples to oranges, but I like James' DataSource example. Here's one from me - does it makes sense? Let's say you are trying to figure out something about the Milky Way. If a function you were passing in as part of this was messy and something that somebody else would want to change for their calculation, say, an estimate of the total mass of the universe, you should curry this out.
Slightly off-topic, but this is a bit of an area where my brain apparently works differently than many. I prefer an API with fewer, more generic methods, but (to counter balance) will accept more parameters to each method. Where others prefer APIs with many, more specific methods, each with fewer parameters. As a Java example, if my class has a java.util.Properties with 3 "well known" keys, "foo", "bar", and "goo", I may define three static Strings to represent them, but the actual API would almost always be
String get(String key);
Many others will "curry" this and write specific getters
> Many others will "curry" this and write specific getters > > String getFoo(); > String getBar(); > String getGoo();
I would say calling this 'currying' is a huge stretch. It achieves the opposite effect of currying. Currying makes it easier to reuse existing code through making it possible for a caller providing n parameters to call one defined with n + m parameters.
The above is as about as far away from that as possible.
Flat View: This topic has 25 replies
on 2 pages
[
«
|
12
]