Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Infinite curryable add function

Tags:

scala

currying

I was wondering how one would implement an infinite curried add function, for the case of explanation i would stick to scala.

I know how to prepare a simple curry like

def add(a: Int): Int => Int = {
  def iadd(b: Int): Int = {
    a + b
  }
  iadd
}
add(4)(5) // 9

How would i got about implementing add(5)(4)(x1)(x2)..(xn)

like image 233
joachim Avatar asked Dec 22 '22 22:12

joachim


2 Answers

The Smart Way

The question is the comments is well-posed: when do you stop the currying and produce a result?

One solution is to stop the recursion by calling the function with zero arguments. Scala's overloading with let us do this.

add(1)(2)(3)(4)() // The () indicates that we're done currying

This is relatively straightforward. We just need a class with an apply that returns a new instance of itself

// A class with an apply method is callable like a function
class Adder(val acc: Int) {

  def apply(a: Int): Adder =
    new Adder(acc + a)

  def apply(): Int =
    acc

}

def add: Adder = new Adder(0)

println(add(1)(2)(3)(4)()) // 10

If you ever had a real reason to do this, this would be the way I would recommend. It's simple, easy to read, and adds very little boilerplate on top of the currying.

The Slightly Unhinged Way

But what fun is simple and logical? Let's get rid of those silly parentheses at the end, eh? We can do it with Scala's implicit conversions. First, we'll need to import the feature, so that Scala will stop warning us that what we're doing is silly and not a good idea.

import scala.language.implicitConversions

Then we make it so that Adder can be converted to Int

// Don't do this in real code
implicit def adderToInt(adder: Adder): Int =
  adder()

Now, we don't need those parentheses at the end. We do, however, need to indicate to the type system that we want an Int.

val result: Int = add(1)(2)(3)(4)
println(result) // 10

Passing the result to a function which takes an Int, for instance, would also suffice.

Comments

Since you mentioned functional programming in general, I will note that you can do similar tricks in Haskell, using typeclasses. You can see this in action in the standard library with Text.PrintF. Note that since Haskell functions always take one argument, you'll need to have a sentinel value to indicate the "end" of the arguments (() may suffice, depending on how generic your argument types are).

like image 88
Silvio Mayolo Avatar answered Dec 25 '22 11:12

Silvio Mayolo


If you want to reinterpret every integer n as function n.+, then just do it:

implicit class Add(val x: Int) extends AnyVal { def apply(i: Int) = x + i }
val add = 0

or even shorter (with implicit conversions):

implicit def asAdd(n: Int): Int => Int = n.+
val add = 0

Example:

add(1)(2)(3)(4) // res1: Int = 10

There is no such thing as "infinitely curryable", it's not a meaningful notion.

like image 45
Andrey Tyukin Avatar answered Dec 25 '22 12:12

Andrey Tyukin