11

I am reading and practicing Scala, and I found this blog.

Reading the part about Composing Predicates I see this piece of code

def complement[A](predicate: A => Boolean) = (a: A) => !predicate(a)

def any[A](predicates: (A => Boolean)*): A => Boolean =
  a => predicates.exists(pred => pred(a))

def none[A](predicates: (A => Boolean)*) = complement(any(predicates: _*))

def every[A](predicates: (A => Boolean)*) = none(predicates.view.map(complement(_)): _*)

I have a python background and would like to understand the meaning of underscore and asterisk, when used alone or together, it's quite strange to make sense of it, specially for none and every definitions.

Diego Rueda
  • 2,226
  • 4
  • 21
  • 41
  • `_` in general means "something whose name I don't care about". You may want to explore this answer regarding all its possible meanings: http://stackoverflow.com/a/8001065/3314107 – stefanobaghino Feb 04 '17 at 00:53

2 Answers2

14

SomeExpression* means "a sequence of 0 or more elements"

_ can be used to specify "a parameter that we do not need to name"

The parameter to none is "a sequence of predicates containing 0 or more elements", and a "predicate" is a function that takes A and returns Boolean.

The parameter to any is an array, so the value passed in must be converted to an array, which is done by _*

The parameter to every is an array, whose name is not important because there is only one. It can be passed to complement as _

radumanolescu
  • 4,059
  • 2
  • 31
  • 44
8
def any[A](predicates: (A => Boolean)*)

produces the same function as

def any[A](predicates: Seq[A => Boolean])

except that you can call it like any(a, b, c) instead of any(List(a, b, c)) (the compiler transforms the call sites).

Given that any is a varargs function, calling any(a) enters the body of any with predicates = List(a). But if a is already a sequence, this isn't what you want. That's what the : _* notation is for: it tells the Scala compiler "treat this as a sequence of parameters for varargs".

This is roughly equivalent to writing in Python,

def complement(predicate):
    return lambda a: not predicate(a)

def any_(*predicates):
    return lambda a: any(pred(a) for pred in predicates)

def none(*predicates):
    return complement(any_(*predicates))

def every(*predicates):
    return none(*map(complement, predicates))
ephemient
  • 198,619
  • 38
  • 280
  • 391
  • 1
    `Seq`, not `Array`. – Alexey Romanov Feb 04 '17 at 15:34
  • @AlexeyRomanov Right, my mistake. `Array` is possible with a `@varargs` annotation for Java comparability, but it's `Seq` for plain Scala code. – ephemient Feb 04 '17 at 15:41
  • what about the definition for **every** where `_` and `_*` are used in the same line? **complement** accepts only one predicate, but isn't `_` a Seq in that context and that's why later on `_*` can be used? That last line is the most difficult to understand. – Diego Rueda Feb 06 '17 at 13:45
  • @DiegoRueda Ah, in that case `complement(_)` is shorthand for `a => complement(a)`. `predicates.view.map(...)` is like `predicates.map(...)` but lazy instead of eager, and returns a `Seq`. Then the `: _*` treatment is just like the previous. – ephemient Feb 06 '17 at 16:48
  • There are [many uses and meanings](http://stackoverflow.com/a/8001065) of the `_` placeholder in Scala. – ephemient Feb 06 '17 at 17:00