Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding Scala's underscore and asterisk magic [duplicate]

Tags:

scala

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.

like image 804
Diego Rueda Avatar asked Feb 03 '17 22:02

Diego Rueda


2 Answers

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 _

like image 103
radumanolescu Avatar answered Oct 11 '22 13:10

radumanolescu


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))
like image 27
ephemient Avatar answered Oct 11 '22 14:10

ephemient