Why calling a function like this works in Scala? - scala

I have the following Scala code snippet:
type Set = Int => Boolean
def contains(s: Set, element:Int): Boolean = s(element)
def singletonSet(element: Int): Set = Set(element)
val oneElementSet = singletonSet(5)
contains(oneElementSet, 5) // true
contains(oneElementSet, 6) // false
I'm trying to wrap my head around what this does: Set(element). Looks like it'll substitute element in place of an Int argument, to produce this: 5 => Boolean. There is no comparison anywhere, so why does oneElementSet(5) returns true, and oneElementSet(6) returns false?
Thanks!

Scala has separate namespaces for types and values. Your type alias defines what Set is in the type namespace, but in the definition of singletonSet Set comes from the value namespace, in fact it is the companion object scala.collection.immutable.Set. Set(element) invokes the apply method of the companion object, which returns a scala.collection.immutable.Set[Int], which turns out to be a subtype of Int => Boolean and therefore is a Set (your type alias) as well.

Related

How to access member variables in nested case classes

I have this code:
case class L2JsonMapping(myTarget: Option[Int])
case class L1JsonMapping(l1: Option[L2JsonMapping])
case class JsonMapping(l0: Option[L1JsonMapping])
Assume that they have been initialized. Now how should I get "myTarget" assigned to "result" in the following function:
def function(in: JsonMapping): Int = {
val result = ?
...
}
Note that I also need to handle Option situation. Thanks.
You'll have to supply a default value to return in case one of the Options is None. Let's assume that default is 0 - if so, you can use:
def function(in: JsonMapping): Int = in.l0 // get Option[L1JsonMapping]
.flatMap(_.l1) // flatMap to get an Option[L2JsonMapping]
.flatMap(_.myTarget) // flatMap to get an Option[Int]
.getOrElse(0) // get value value or default
This uses Option.flatMap which you can read about in the ScalaDocs:
Returns the result of applying [the given function] f to this scala.Option's value if this scala.Option is nonempty. Returns None if this scala.Option is empty.
NOTE that this simply returns the value of myTarget - I'm assuming you're assigning it to result just to return result immediately - if so, that's redundant.

conflict alias for Set and traditional Scala Set

I am a newbie and I will try to be as clear as possible. This is about odersky scala course.
I have this code below. I understand that this is an alias type to define a Scala Set differently that the traditional way you define a Set in Scala(i.e. a Scala collection). In this type alias, you give it a integer and returns true (somehow) if the item is contained in the Set.
type Set = Int => Boolean
Now I have this piece of code, which returns the result i am expecting.
val a = Set("element is contained in set")
type Set = Int => Boolean
a.contains("element is contained in set")
a.contains("element IS NOT contained in set")
The result is:
a: scala.collection.immutable.Set[String] = Set(element is contained in set)
defined type alias Set
res0: Boolean = true
res1: Boolean = false
res2: scala.collection.immutable.Set[String] = Set(element is contained in set)
Great! Now i introduce a line in the code.
val a = Set("element is contained in set")
type Set = Int => Boolean
a.contains("element is contained in set")
a.contains("element IS NOT contained in set")
**def custom_fc(x:Double): Set[String] = Set(x.toString)**
I get the error:
Error:(8, 24) A$A235.this.Set does not take type parameters
def custom_fc(x:Double): Set[String] = Set(x.toString)
Error:(38, 97) inst$A$A.Set does not take type parameters
println("custom_fc: " + MacroPrinter211.printGeneric({import inst$A$A._ ;def `custom_fc(x:Double): Set[String] = Set(x.toString) }).replace("inst$A$A.", ""))`
WHY? In this line i am just trying to define a regular fc (i.e. custom_fc) taking Int as input and returning a traditional scala datastructure Set[String]
type Set = Int => Boolean
**def custom_fc(x:Double): Set[String] = Set(x.toString)**
Why does my custom fc definition interfere with the alias before it?
My custom_fc is
custom_fc(x:Double): scala.collection.immutable.Set[String] =
scala.collection.immutable.Set(x.toString)
thank you
ps. a way to use Type Set = Int => Boolean
val belowNegFive: Set = (i) => i < -5
belowNegFive(10)
Return a bool dependinf if the elem 10 pertains to the set of numbers below -5.
Here's what's going on.
val a = Set("element is contained in set") // a is old library Set()
type Set = Int => Boolean // alias now hides library Set()
a.contains("element is contained in set") // a is still old library
a.contains("element IS NOT contained in set") // and works like it should
def custom_fc(x:Double): Set[String] = Set(x.toString) // WRONG
// new Set alias works different from old library Set()
The point of the class is to work with functions. The Set alias is a function definition: Int => Boolean i.e. takes an Int and returns a Boolean.
The new Set alias is very different from the Set collection and can't be used the same way. The Set alias does appear to imitate the collection only in that you can query its "content" in the same way, but only when working with Int values. Even then, the means of initialization is different.
val libSet: collection.Set[Int] = Set(7) // initialize with a 7
type Set = Int => Boolean
val newSet: Set = (x:Int) => x == 7 // initialize with a 7
libSet(7) // true
libSet(4) // false
newSet(7) // true
newSet(4) // false
The library collection works with other types but the Set alias only takes an Int and returns a Boolean. The new Set is a type alias for a function definition. An instance of the new Set is a function that imitates only a small subset of what the real Set does.
So you're obviously overriding the Set alias that was already in place. You can fix this by as mentioned in the comments, specifying exactly which Set you mean.
def custom_fc(x:Int): scala.collection.immutable.Set[String] = Set(x.toString)
Also note your type alias is not doing anything. Your calls a("element is contained in set")
a("element IS NOT contained in set") are just calling the apply method on a, which is the same thing as doing a.apply(...) and a.contains(...) In order to make it easier on yourself and less confusing overall, maybe change the name to Contains?
To see an example of your set being used, here you go...
val setBeingUsed: Set = Set(1).contains
setBeingUsed(1) // true
The method which takes in an Int and returns a boolean can be assigned the type Set because you aliased that type to it. Then we can call the val we made with type Set and essentially do the same thing as calling contains on the set.

Scala Else return function

I'm taking the Coursera FP Principles in Scala course, and I'm having trouble with the last function in the week 2 assignment. I don't want the answer, but rather some help in understanding Scala functional composition. I think I have the right idea as to how to solve the problem, I'm just getting tripped up on the Scala-specific part.
The gist is: We've been given a type alias, defined as such:
type Set = Int => Boolean
Which I've interpreted to mean a Set is a function that takes an Int and returns a Bool.
We've also been tasked with finishing the function singletonSet, which takes an int and returns a Set. I've written it as such
def singletonSet(x: Int): Set = Set(x)
val three = singletonSet(3)
three(3) //True
three(5) //False
The function I'm having trouble with is the Map function, which has this signature:
def map(s: Set, p: Int => Int): Set
Which I've interpreted to mean A function that takes a set, transforms its elements with function P, and returns a new Set.
The pesudocode: Map returns a function that takes an int, and if that int exists in Set s, return a new Set with the transformed int X (or p(x)
The actual code that's breaking:
def map(s: Set, p: Int => Int): Set = {
x =>
if (s(x)) singletonSet(p(x))
else p(x) => false
}
The error that I'm getting with this format is:
error: not a legal formal parameter.
Note: Tuples cannot be directly destructured in method or function parameters.
Either create a single parameter accepting the Tuple1,
or consider a pattern matching anonymous function: `{ case (param1, param1) => ... }
else p(x) => false
I'm not grokking what's wrong with my implementation. A friend wrote my logic out in Haskell and found it to be successful, so I think my algorithm is correct (although I could be wrong). I'm struggling with the Scala implementation details. Any advice or guidance is much appreciated.
Remember that you're dealing with a Set here, and Set is defined as a function that converts an Int to a Boolean. Therefore, your function needs to return the same thing:
def map(s: Set, p: Int => Int): Set = {
x =>
if (s(x)) singletonSet(p(x)) // Returns a Set
else p(x) => false // Returns a Boolean
}
We can see that despite the input, you have two different output cases, which we know must be wrong. Now, lets also recall that you have other functions, and your definition of set and 'expand' what you're building:
def map(s: Set, p: Int => Int): (Int) => (Boolean) //Expand 'Set' to int->boolean
= (x: Int) => (Something that returns a boolean)
Your job is to figure out what that 'something' is, based on the semantics of map. I highly recommend looking around at other functions that return a boolean and ask how they might apply here. Specifically, you're looking for a function that will, for any integer provided, give you a transformation if that integer exists within the original set.

Trying to skip implicit parameter list

I'd like to call a function returned by a function with an implicit parameter, simply and elegantly. This doesn't work:
def resolveA(implicit a: A): String => String = { prefix =>
s"$prefix a=$a"
}
case class A(n: Int)
implicit val a = A(1)
println(resolveA("-->")) // won't compile
I've figured out what's going on: Scala sees the ("-->") and thinks it's an attempt to explicitly fill in the implicit parameter list. I want to pass that as the prefix argument, but Scala sees it as the a argument.
I've tried some alternatives, like putting an empty parameter list () before the implicit one, but so far I've always been stopped by the fact that Scala thinks the argument to the returned function is an attempt to fill in the implicit parameter list of resolveA.
What's a nice way to do what I'm trying to do here, even if it's not as nice as the syntax I tried above?
Another option would be to use the apply method of the String => String function returned by resolveA. This way the compiler won't confuse the parameter lists, and is a little shorter than writing implicltly[A].
scala> resolveA[A].apply("-->")
res3: String = --> a=A(1)

Why is a Set a function?

In Scala a Set is a function:
trait Set[A] extends (A => Boolean)
This make it impossible to have a covariant immutable Set because type A occurs in contravariant position. In contrast Seq is not defined as a function. There is already some content about the question why Sets and Seqs are designed this way:
Why is Scala's immutable Set not covariant in its type?
Scala: Why does Seq.contains take an Any argument, instead of an argument of the sequence type?
Why does Seq.contains accept type Any rather than the type parameter A?
One answer says that the reason for this is the mathematical background. But this answer wasn't explained a little more. So, what are the concrete advantages to define a Set as a function or what would be the disadvantages if it is implemented differently?
The set of type Set[A] has to have a method that tests if an element of type A is in the set. This method (apply) has to have a parameter of type A representing that element, and that parameter is in the contravariant position. This means that sets cannot be covariant in their type parameter A. So - it's not the extending of the function interface that makes it impossible to have covariant immutable sets, it's the existence of the contravariant apply method.
And for reasons of convenience, it makes sense to extend the Function1 interface to be able to pass sets around and treat them as functions.
By contrast, sequence abstraction doesn't have a method that tests if an element is in the sequence, it only has the indexing method - apply takes an integer index, and returns the element at that index. Sequences are also defined as functions, but functions of type Int => A (which are covariant in A), not A => Boolean, as sets.
If you want to know more about how type safety would be broken if sets were defined as covariant in their type parameter A, see this example in which the set implementation does some writing to private members for reasons of caching the lookups (below #uV is the annotation which disables variance checking and expensiveLookup is meant to simulate a call to a computationally expensive check if an element is in the set):
import annotation.unchecked.{uncheckedVariance => uV}
trait Set[+A] {
def apply(elem: A #uV): Boolean
}
class CachingSet[+A >: Null] extends Set[A] {
private var lastLookup: (A #uV, Boolean) = (null, false)
private def expensiveLookup(elem: A #uV) = (elem, true)
def apply(elem: A #uV): Boolean = {
if (elem != lastLookup._1) lastLookup = expensiveLookup(elem)
lastLookup._2
}
def lastQueriedElement: A = lastLookup._1
}
object Main extends App {
val css = new CachingSet[String]
val csa: CachingSet[AnyRef] = css
csa.apply(new AnyRef)
val s: String = css.lastQueriedElement // you'll get a ClassCastException here
}
In contrast Seq is not defined as a function.
Not true.
Seq[T] extends (Int) => T