0

I am reading the Scala with Cats book available here: https://books.underscore.io/scala-with-cats/scala-with-cats.html

There is a code sample in the book that I have a question about.

Basically, there is an extra underscore in the code whose purpose I don't understand. Is it a typo, or does the underscore serve some purpose?

import cats.Monoid
import cats.instances.int._        // for Monoid
import cats.instances.invariant._  // for Semigroupal
import cats.instances.list._       // for Monoid
import cats.instances.string._     // for Monoid
import cats.syntax.apply._         // for imapN

case class Cat(
  name: String,
  yearOfBirth: Int,
  favoriteFoods: List[String]
)

val tupleToCat: (String, Int, List[String]) => Cat =
  Cat.apply _

val catToTuple: Cat => (String, Int, List[String]) =
  cat => (cat.name, cat.yearOfBirth, cat.favoriteFoods)

implicit val catMonoid: Monoid[Cat] = (
  Monoid[String],
  Monoid[Int],
  Monoid[List[String]]
).imapN(tupleToCat)(catToTuple)

I am referring to the definition of the tupleToCat class. What is the purpose of the underscore after Cat.apply?

Allen Han
  • 1,163
  • 7
  • 16
  • 2
    Basically it is to force the eta-expansion, to transform a method into a function. The code is equivalent to: `val tupleToCat: (String, Int, List[String]) => Cat = (name, yearOfBirth, favoriteFoods) => Cat.apply(name, yearOfBirth, favoriteFoods)`. - Note, at least for **Scala 2.13**, you do not need the `_`, not even the call to `apply`, you can just pass `Cat`. Maybe older versions of Scala needed it, or it was there just for clarity. – Luis Miguel Mejía Suárez Aug 06 '19 at 23:34

2 Answers2

1

In scala lambda functions (or anonymous functions like tupleToCat in your example), _ acts as the name of the list of parameters to that function. So in that case Cat.apply _ means call Cat.apply with all of the arguments passed to tupleToCat.

Underscore is more powerful than that. See here for more info

mkhanoyan
  • 1,958
  • 18
  • 15
0

Is the way to convert a method into a function. Cat.apply is a method from the companion object Cat that receives a String (the name), an Int (yearOfBirth) and a List[String] (favorite foods) and returns a Cat. When you do Cat.apply _ to convert the method into a function.

You could also use curried and then use partial applied functions to get a function that receives a yearOfBirth and a list of favorite foods and returns a Cat with name Tom.

val curried: String => Int => List[String] => Cat = Cat.curried

val alwaysTom = curried("Tom")

val tom = alwaysTom(1)(List("fish"))
val olderTom = alwaysTom(10)(List("fish","rice"))

You can also use partially applied functions without curried

val alwaysTom: (Int, List[String]) => Cat = Cat.apply("tom",_:Int,_:List[String])
gabrielgiussi
  • 9,245
  • 7
  • 41
  • 71