3

I'm having difficulty understanding how curried functions (with one argument) differ from normal methods. I tried to implement the latter with the former, but wasn't able to.

I have Market trait defined as follows:

package market {
  trait Market {
    def getBuyRate(currency: String): Double
    def getSellRate(currency: String): Double
  }
}

I have another FakeMarket trait that extends Market where I wanted to use currying to implement getBuyRate and getSellRate, as follows:

package market { 
  trait FakeMarket extends Market with Iterable[Double] {
    def getRate(factor: Double)(currency: String): Double = {
      factor * this.iterator.next()
    }
    def getBuyRate = getRate(1) _
    def getSellRate = getRate(1.02) _
  } 
}

Finally, I have RandomFakeMarket object that extends FakeMarket:

package market {
  object RandomFakeMarket extends FakeMarket {
    def iterator = new Iterator[Double] {
      def hasNext = true
      def next = 100.0
    }
  }
}

Having the types defined as such gives an error saying:

<console>:10: error: object creation impossible, since:
it has 2 unimplemented members.
/** As seen from object RandomFakeMarket, the missing signatures are as follows.
 *  For convenience, these are usable as stub implementations.
 */
  def getBuyRate(currency: String): Double = ???
  def getSellRate(currency: String): Double = ???

       object RandomFakeMarket extends FakeMarket {
              ^

This seems odd to me because FakeMarket implements methods called getBuyRate and getSellRate of String => Double type.

I can get this to work if in Market I had done:

getBuyRate: String => Double

Why is this different from how I originally defined getBuyRate? Why should this be different when there's only one argument? Now it seems that the parent trait Market has to worry about how getBuyRate gets implemented (a normal function vs a curried function).

Jacek Laskowski
  • 72,696
  • 27
  • 242
  • 420
Veech
  • 1,397
  • 2
  • 12
  • 20
  • Why is this different? In Scala, methods and functions are different things (e.g., functions cannot take type parameters), and as such, you can't just use a function where a method is required. – Hugh Dec 21 '14 at 03:12

1 Answers1

4

It's not so much related to currying. def method(p1: String, p2: String): String is not equivalent to def method: (String, String) => String in scala. The difference between methods and functions is that methods support inheritance, so they need to know the method's input and output, which is not so obvious because of ambiguity:

def get: String => Double may be both String -> Double (iterpreted as unified member) and () -> String -> Double (interpreted as function). But in scala it's Function1[String, Double] or () Function1[String, Double], which are simmilar in the meaning that there is no input. Unfortunatelly, def get(): String => Double makes no difference here (see examples below).

In other words, method may not have input parameters in scala (as it's may not be a pure function because of side effects), so it can't infer (String)Double from String => Double so your whole function becomes an output parameter. For example you could do override def method: (String, String) => String in some subclass - this will override method without parameters and with return type (String, String) => String, but not override the method with input (String, String) and return type String.

Another problem is that methods have different types than functions and may be only one-way converted by eta-expansion, so scala is a little bit incompatible with UAP :

scala> def aaa(b: String): String = "aaa"
aaa: (b: String)String

scala> aaa _
res4: String => String = <function1>

scala> def aaa: String => String = (a: String) => "aa"
aaa: String => String

scala> def aaa()(b: String): String = "aaa"
aaa: ()(b: String)String

scala> def aaa(): String => String = (a: String) => "aa"
aaa: ()String => String

A bit more about methods vs functions: Difference between method and function in Scala

Community
  • 1
  • 1
dk14
  • 22,206
  • 4
  • 51
  • 88
  • Thanks! So is there a way to do what I was trying to do earlier by reusing code to implement getBuyRate and getSellRate via currying? I guess for now I could just do `getBuyRate(x: String) = getRate(1.0, x)` – Veech Dec 21 '14 at 05:02
  • You're welcome). Sure, it will be `(String)Double`, so there is no problem with such polymorphism. – dk14 Dec 21 '14 at 05:33