Advertisement
3-CodeJugalbandi-currying-pfa-healthycodemagazine#mar2015
3-CodeJugalbandi-currying-pfa-healthycodemagazine#mar2015
3-CodeJugalbandi-currying-pfa-healthycodemagazine#mar2015
3-CodeJugalbandi-currying-pfa-healthycodemagazine#mar2015
Upcoming SlideShare
4-Code-Jugalbandi-destructuring-patternmatching-healthycode#apr20154-Code-Jugalbandi-destructuring-patternmatching-healthycode#apr2015
Loading in ... 3
1 of 4
Advertisement

More Related Content

Advertisement
Advertisement

3-CodeJugalbandi-currying-pfa-healthycodemagazine#mar2015

  1. Healthy Code March - 2015 10 In 2013, Dhaval Dalal was inspired by Jugalbandi, an Indian classical music form in which musicians have an improvised musical conversation, each using a different instrument, while exploring a shared musical theme together akin to Jazz in some ways. Dhaval thought, “What if we could have a conversation about some programming concepts in this way? Instead of musical instruments, what if we use different programming languages?” Code Jugalbandi Article Ryan and Dhaval
  2. Healthy Code March - 2015 11 Creator and Listener We met regularly with over a period of several months, exploring some key issues related to Functional Programming(FP).ThisculminatedinaliveCodeJugalbandi at the Functional Conference in Bengaluru, 2014. During the FP Code Jugalbandi, we explored nine themes, which becamemelodies. Similar to the musical Jugalbandi, there are two roles: creator and listener. We called the creator of the melody Bramha and the one who listens and responds with a different instrument, Krishna. In the last Code Jugalbandi Article, we looked at the melody, the Sequencing problem. This time we will look at Currying and Partial Function Application (PFA). Currying in Groovy BRAMHA: Imagine, I have an HTTP request for a customer in our web application and we want to authorize the request.I’ll use Groovy here to do that. def req1 = [‘id’: 1] def customer = authorizer(repo, req1) println customer.name BRAMHA: Let’s write down the customer repository quickly. class CustomerRepository { def findBy(Integer id) { if(id > 0) { [id: id, name: “Cust Name #$id”] } else { throw new RuntimeException(‘cust not found’) } } } BRAMHA: and I’ll write authorizer as a closure that consumes two parameters, repository and request. def authorizer = { rep, req -> rep.findBy(req.id) } BRAMHA: Now let’s say that, before I can request the customer, I need to make sure that the user is authorized to access it. def repo = new CustomerRepository() def req1 = [‘id’: 1] def req2 = [‘id’: 2] def cust1 = authorizer(repo, req1) def cust2 = authorizer(repo, req2) BRAMHA: If you look at the above. I’m repeatedly injecting CustomerRepository reference when calling authorizer. Could I somehow convert this authorizer to just accept request; the parameter that varies while fixing the repository? This is where I’ll resort to currying the repository. def auth = authorizer.curry(repo) def cust1 = auth(req1) def cust2 = auth(req2) BRAMHA: I’ve re-shaped the authorizer to a single argument function from a two-argument function. Along similar lines I’ll write an authenticator that takes in an authorizer and http- request and re-shape it to just accept request. def authenticator = { rep, req -> rep(req) } def auth = authenticator.curry(authorizer. curry(repo)) def cust1 = auth(req1) BRAMHA: We used currying to re-shape the functions so that we can chain them and the request can flow through each of them. BRAMHA: Let me show you some Scala code that does the same thing. Currying in Scala case class Customer(id: Int, name: String) class CustomerRepository { def findBy(id: Int): Option[Customer] = if (id > 0) Some(Customer(id, s”Customer Name # This led to the first Code Jugalbandi between us. Code Jugalbandi inspired and fuelled our learning by focussing on dialogue and exploration. More languages in the room meant more perspectives too. Exploring a paradigm through many languages gave us a better map of the territory than any single language could. Above all, Code Jugalbandi was a playful way to learn together!
  3. Healthy Code March - 2015 12 KRISHNA: With partial function application, and currying, for that matter, the order of arguments matter! e.g. what if we wanted to fix the second argument instead of the first? (def new-ada (partial new-person title “Ada”)) (new-ada “Ms” “Lovelace”) KRISHNA: But this doesn’t make sense, because we somehow need to have a placeholder for the first param, which we don’t want to partially apply. So, when we’re partially applying argument to a function, it works from left to right. We can’t only apply the third argument and not also the first and second arguments. We can wire in values for the arguments, from left to right. We can’t wire in only the second param, but I can always achieve this with a lambda: (def new-ada (fn [title lname] (new-person title “Ada” lname))) (new-ada “Ms” “Lovelace”) KRISHNA: Fortunately, Clojure has a macro to synthesise this kind of “ad-hoc” partial function application: (def new-ada-f #(new-person %1 “Ada” %2)) (new-ada-f “Ms” “Lovelace”) KRISHNA: I’m sure Scala has this kind of thing too, right? Partial Function Application in Scala BRAMHA: Sure, let me show this in Scala. I do partial functionapplicationonnew_personbyputtinginplaceholders for its second and third parameters, and just bind title def new_person(title: String, fname: String, lname: String) = s”$title $fname $lname” val new_ms = new_person(“Ms”, _: String, _: String) new_ms(“Ada”, “Lovelace”) BRAMHA This time, I do partial function application on fname by putting in placeholders for its first and last parameters. val new_ada = new_person(_: String, “Ada”, _: String) new_ada(“Ms”, “Lovelace” KRISHNA: Scala’s syntax is definitely superior to Clojure’s in the sense that regular and ad-hoc partial function application is unified. BRAMHA: Also, in Scala, if you have a function in curried form, that is, a function of one argument at a time, it’s trivial to convert it to the uncurried form, and vice versa. $id”)) else None } type Request = Map[String, Int] def authenticator(f: Request => Option[Customer]) (req: Request): Option[Customer] = f(req) def authorizer(rep: CustomerRepository)(req: Request): Option[Customer] = req.get(“id”). flatMap(id => rep.findBy(id)) val authorize = authorizer _ val authenticate = authenticator _ val auth = authenticate(authorize(new Customer Repository)) val req1 = Map(“id” -> 1) val cust1 = auth(req1) BRAMHA: If you observe the above code, unlike Groovy, I don’t invoke any special method to do currying, by using multi-parameter functions, Scala gives you currying for free. All I do here is convert the methods authorizer and authenticator to function type using partial function application by using underscore(). This gives me _ authorize, having type CustomerRepository (Request Option[Customer])functionobject.Italsogivesmeauthenticate, having type (Request Option[Customer]) (Request Option[Customer]) function object. Itheninjecttherepositoryinauthorizeandbecauseofcurrying it then gets re-shaped into a function that goes from Request Option[Customer]. This type then directly aligns as input parameter to the authenticate function. Partial Function Application in Clojure KRISHNA: Let’s look at partial function application in Clojure and start with this function with three arguments. (defn new-person [title f-name l-name] { :title title, :f-name f-name, :l-name l-name }) (new-person “Ms” “Ada” “Lovelace”) KRISHNA: What if I wanted to partially apply the title to this function? (def new-ms (partial new-person “Ms”)) (new-ms “Ada” “Lovelace”) KRISHNA: I’ve reshaped the function by wiring in the first argument.
  4. Healthy Code March - 2015 13 val fUncurried = Function.uncurried(f) val fCurried = fUncurried.curried Currying in Haskell KRISHNA In Haskell, functions are curried by default, you don’t have any special syntax like Scala. make_person :: String -> String -> String -> String make_person s fname lname = s ++ fname ++ lname main = putStrLn (make_person “Ms” “Ada” “Lovelace”) -- above is same as main = putStrLn ((make_person “Ms”) “Ada” “Lovelace”) -- is same as main = putStrLn (((make_person “Ms”) “Ada”) “Lovelace”) BRAMHA: Groovy also offers right curry - rcurry and curry a particular parameter at a position - ncurry, but I think they are more like PFArather than actual currying that we usually see from left to right. Reflections KRISHNA This shows the difference between Currying and PFA. With PFA, we are just dealing with regular functions of multiple arguments; essentially fixing a few arguments and returning a function with fewer arguments. However, Currying refers to functions that take only one argument at a time! You can think of a Curried function as a nested structure, just like Russian dolls: for each argument, there is another nested function, that takes that argument and returns a function taking the subsequent arg, and so on, until all the arguments are exhausted. BRAMHA: In FP, we can achieve Dependency Injection (DI) by passing functions around and thereby injecting behaviour. But currying and PFA also offer a way to achieve DI: for a function that takes either functions as arguments or just regular parameters, when we curry such an argument, we are injecting dependency.Also, depending on the context, we can change the concrete dependency. For example, when the context is driving design through tests, we can inject a MockCustomerRepository, whereas in production we would inject the real CustomerRepository. KRISHNA: Yes, that’s why it’s quite commonly used in web frameworks to inject locale and other contextual information when creating a request. BRAMHA: In a language that deals well with PFA, you won’t really miss currying, because you’ll use PFA where you would have used currying. Also, “ad-hoc PFA” is practically more powerful than currying in some ways. With currying, you have to curry strictly from left to right, with PFA you can do ad-hoc application of args. KRISHNA: Currying and PFA gives us a way to reshape - and repurpose - our functions for different use cases, without having to explicitly “wrap” the old function with a different argument list. References Learn more from http://codejugalbandi.org Ryan is a software developer, coach and advisor, based in Cape Town. He has been working with code for more than 15 years. Ryan assists individuals and teams to manage the evolution and complexity of their software systems. Ryan is a passionate learner and enjoys facilitating learning in others. Dhavalahands-ondeveloperand mentor, believes that software development is first an art and then a craft. For him writing software brings his creativity to the fore. His interests are in architecting applications ground up, estabilishing environments, transitioning and orienting teams to Agile way of working by embedding himself within teams. You can follow them on Twitter @ CodeJugalbandi
Advertisement