I am working on Coursera Assignment and in Week 2. This week assignment is not tough but very confusing.
I wrote below code and it works fine
def union(s:Set[Int], t:Set[Int]):Set[Int] = s union t
But if I use type to create alias of Set and rewrite above as
type Set = Int => Boolean
def union(s:Set, t:Set):Set = s union t
Now I get error for union is not a member of Set
def union(s:Set[Int], t:Set[Int]):Set[Int] = s union t
This works because Set[T] defines a function named union, which is called in the above code.
type Set = Int => Boolean
def union(s:Set, t:Set):Set = s union t
This doesn't work because functions don't have a method named union.
From what I can remember way back when I did that course, you are not supposed to use any standard library types to build your solutions. So you are not supposed to use Set[T] from the standard library. In the collection library, union is defined and works as expected.
However, the course requires you to define your own type for Set and I believe it is Int => Boolean.
What you actually need is a function like this:
type Set = Int => Boolean
def union (s1 : Set, s2 : Set) : Set = (x:Int) => s1(x) || s2(x)
That is, you need to define a lambda.
You already have union function present in scala. You can verify in repl by doing:
> val x: Set[Int] = Set(1,2,3)
> x.union(Set(3, 4, 5))
res0: scala.collection.immutable.Set[Int] = Set(5, 1, 2, 3, 4)
Let's say you want to define your own function to do exactly the same thing, you can write:
def myunion[T](x: Set[T], y: Set[T]): Set[T] = x.union(y)
This is generic method(just like in set) and you can call it:
> myunion(Set(1, 2, 3), Set(3, 4, 5))
//but it also works for other types:
> myunion(Set('a', 'b', 'c'), Set('c', 'd', 'e'))
Aliasing type is done with slightly different syntax:
type SetInt = Set[Int]
type SetChar = Set[Char]
When you do type Set = Int => Boolean, you create Function1 type.
You can check it by yourself in scala repl;
scala> type Set = Int => Boolean
defined type alias Set
scala> val test: Set = i => true
test: Set = <function1>
As you see in Function1[-T1, +R] trait extends AnyRef which doesn't have union method but Set has it.
Related
In scala if I have a declaration such as this:
val i: Float = 5
Is this the same like in this line:
val i = 5: Float
?
Recently I encountered an expression with such type annotation on the right side and I wonder what its usage is as I could not find it in the specs.
This is called type ascription and it's meant to disambiguate types when several options might be available.
A typical example is a fold:
val l = 1 to 5
val stringyfied = l.foldLeft(Nil)((list, elem) => elem.toString :: list)
What is the type of Nil in that case? If you try that example, the compile will bark with an error:
error: type mismatch;
found : List[String]
required: scala.collection.immutable.Nil.type
We can make the specific type known to the compiler by using type ascription:
val stringyfied = l.foldLeft(Nil:List[String])((list, elem) => elem.toString :: list)
// stringyfied: List[String] = List(5, 4, 3, 2, 1)
Another common use is to view a collection as a vararg as in:
def varargs(a:Int*) = a.sum
// common use:
varargs(1,2,3,4,5) //15
// now we have a collection of elements:
val intlist = 1 to 5
// we cannot call varagrs with a list
varargs(intlist)
> found : List[Int]
> required: Int
// then using type ascription:
varargs(intlist: _*)
To my knowledge, there's not much specific documentation about type ascription other than the specification of the algebra of expressions SLS#Chapter6
This syntax is used to assign types to expressions (while val i: Float = 5 assigns a type to a term). It can make a difference when you do it with a part of a bigger expression.
scala> implicit class WeirdFloat(f: Float) {
| def +(ff: Float) = new WeirdFloat(f + ff * 2)
| override def toString = s"$f"
| }
defined class WeirdFloat
scala> val i: WeirdFloat = 5 + 7
i: WeirdFloat = 12.0
scala> val i = (5: WeirdFloat) + 7
i: WeirdFloat = 19.0
I believe the only difference is that the type of i is inferred (by the compiler) from the value in the second example, whereas in the first you are being explicit about the type of i.
The stye guidelines encourage the use of type of inference wherever possible. However, it also mentions that the syntax whereby you follow the value with the type is the approach when you are using ascription - a compile time upcast.
scala> val s = "Jane"
s: String = Jane
scala> val p = s: Object
p: Object = Jane
What's the verbose way for val Singleton4 : Set = set => set == 4? I am unable to understand where the set parameter is coming from.
What maybe confuses you is the fact that Set is not what one would expect from the Scala library. You should read the line as:
val Singleton4: Int => Boolean = someArbitraryName => someArbitraryName == 4
// <identifier> <type> = <argument> => <returnValue>
It's not "coming" from anywhere, Set is defined as a function from an integer to a boolean and the type of Singleton4 is exactly that, it takes an integer and returns a function which needs another integer and returns a boolean:
scala> type Set = Int => Boolean
defined type alias Set
scala> def singletonSet(elem: Int): Set = set => set == elem
singletonSet: (elem: Int)Int => Boolean
scala> val p: Set = singletonSet(3)
p: Int => Boolean = <function1>
So now p is a function which takes an integer:
scala> p(3)
res0: Boolean = true
scala> p(2)
res1: Boolean = false
An alternative way of writing that is this:
def singletonSet(elem: Int) = (i: Int) => i == elem
val p: (Int) => Boolean = singletonSet(3)
Or using a different way but achieving the same result:
def singletonSet(elem: Int)(i: Int): Boolean = i == elem
val p: (Int) => Boolean = singletonSet2(3)
By currying the function and applying only one argument you get back a function which still needs another integer to be fully evaluated.
The other answers are very good, but I thought I'd throw some additional details to help newcomers to Scala understand the notation better (as there are some hidden gems in the notation that were not uncovered/described).
Let's play the Scala compiler game!
The following val says enough about what Set the type represents.
val Singleton4: Set = set => set == 4
The type of val is given explicitly - it's Set. We don't however know much about it...yet. It has however to be given to the compiler before it can be used and given the left-hand side it's a function (mind the => two-letter string) from a type (we'll get to it in a moment) to Boolean since set == 4 will inevitably end as Boolean.
From set == 4 we can deduce that set can only be Int (so you can compare apples to apples) and hence we've got the type of set as Int.
The right-hand side of = of the val could also have been written as:
val Singleton4: Set = (set: Int) => set == 4
So, the Singleton4 val is an instance of a function Int => Boolean that's called Set. Set's declared as such somewhere above (lexicographically):
type Set = Int => Boolean
You could substitute Set to the type alias and end up with:
val Singleton4: Int => Boolean = (set: Int) => set == 4
Is there a syntax to allow generic type parameters on function literals? I know I could wrap it in a method such as:
def createLongStringFunction[T](): (T) => Boolean = {
(obj: T) => obj.toString.length > 7
}
but then I end up needing to invoke the method for every type T and getting a new function. I looked through the language reference, and while I see that the function literal syntax is translated by the compiler to an instance of a Functionn object that itself has generic input types, it looks like the compiler magic realizes those parameters at the time of creation. I haven't found any syntax that allows me to, in effect, "leave one or more of the type parameters of Functionn unbound". What I would prefer is something along the lines of:
// doesn't compile
val longStringFunction: [T](T) => Boolean = (obj: T) => obj.toString.length > 7
Does any such thing exist? Or for that matter, what is the explicit type of an eta-expansion function when the method being expanded has generic parameters?
This is a purely contrived and useless example. Of course I could just make the function use Any here.
No, type parameters only apply to methods and not function objects. For example,
def f[T](x: T) = x //> f: [T](x: T)T
val g = f _ //> g: Nothing => Nothing = <function1>
// g(2) // error
val h: Int=>Int = f _ //> h : Int => Int = <function2>
h(2) //> res0: Int = 2
The method f cannot be converted to a polymorphic function object g. As you can see, the inferred type of g is actually Function1[Nothing, Nothing], which is useless. However, with a type hint we can construct h: Function1[Int,Int] that works as expected for Int argument.
As you say, in your example all you're requiring is the toString method and so Any would be the usual solution. However, there is call for being able to use higher-rank types in situations such as applying a type constructor such as List to every element in a tuple.
As the other answers have mentioned, there's no direct support for this, but there's a relatively nice way to encode it:
trait ~>[A[_],B[_]] {
def apply[X](a : A[X]) : B[X]
}
type Id[A] = A //necessary hack
object newList extends (Id ~> List) {
def apply[X](a : Id[X]) = List(a)
}
def tupleize[A,B, F[_]](f : Id ~> F, a : A, b : B) = (f(a), f(b))
tupleize(newList, 1, "Hello") // (List(1), List(Hello))
Since longStringFunction defined as followed is a value, which must have some given type.
val longStringFunction: (T) => Boolean = (obj: T) => obj.toString.length > 7
However, you can reuse a function object with a method:
scala> val funObj: Any => Boolean = _.toString.size > 7
funObj: Any => Boolean = <function1>
scala> def typedFunction[T]: T => Boolean = funObj
typedFunction: [T]=> T => Boolean
scala> val f1 = typedFunction[String]
f1: String => Boolean = <function1>
scala> val f2 = typedFunction[Int]
f2: Int => Boolean = <function1>
scala> f1 eq f2
res0: Boolean = true
This works because trait Function1[-T1, +R] is contravariant of type T1.
In scala, Function values are parametrically monomorphic(while methods are polymorphic)
Shapeless library introduces polymorphic function values which may be mapped over HLists and many more other features.
Please consider the following refs:
http://www.chuusai.com/2012/04/27/shapeless-polymorphic-function-values-1/
http://www.chuusai.com/2012/05/10/shapeless-polymorphic-function-values-2/
A while back this was asked and answered on the Scala mailing list:
Kevin:
Given some nested structure: List[List[...List[T]]]
what's the best (preferably type-safe) way to flatten it to a List[T]
Jesper:
A combination of implicits and default arguments works:
case class Flat[T, U](fn : T => List[U])
implicit def recFlattenFn[T, U](implicit f : Flat[T, U] = Flat((l : T)
=> List(l))) =
Flat((l : List[T]) => l.flatMap(f.fn))
def recFlatten[T, U](l : List[T])(implicit f : Flat[List[T], U]) = f.fn(l)
Examples:
scala> recFlatten(List(1, 2, 3))
res0: List[Int] = List(1, 2, 3)
scala> recFlatten(List(List(1, 2, 3), List(4, 5)))
res1: List[Int] = List(1, 2, 3, 4, 5)
scala> recFlatten(List(List(List(1, 2, 3), List(4, 5)), List(List(6, 7))))
res2: List[Int] = List(1, 2, 3, 4, 5, 6, 7)
I have been looking at this code for a while. I cannot figure out how it works. There seems to be some recursion involved... Can anybody shed some light? Are there other examples of this pattern and does it have a name?
Oh wow, this is an old one! I'll start by cleaning up the code a bit and pulling it into line with current idiomatic conventions:
case class Flat[T, U](fn: T => List[U])
implicit def recFlattenFn[T, U](
implicit f: Flat[T, U] = Flat((xs: T) => List(xs))
) = Flat((xs: List[T]) => xs flatMap f.fn)
def recFlatten[T, U](xs: List[T3])(implicit f: Flat[List[T], U]) = f fn xs
Then, without further ado, break down the code. First, we have our Flat class:
case class Flat[T, U](fn: T => List[U])
This is nothing more than a named wrapper for the function T => List[U], a function that will build a List[U] when given an instance of type T. Note that T here could also be a List[U], or a U, or a List[List[List[U]]], etc. Normally, such a function could be directly specified as the type of a parameter. But we're going to be using this one in implicits, so the named wrapper avoids any risk of an implicit conflict.
Then, working backwards from recFlatten:
def recFlatten[T, U](xs: List[T])(implicit f: Flat[List[T], U]) = f fn xs
This method will take xs (a List[T]) and convert it to a U. To achieve this, it locates an implicit instance of Flat[T,U] and invokes the enclosed function, fn
Then, the real magic:
implicit def recFlattenFn[T, U](
implicit f: Flat[T, U] = Flat((xs: T) => List(xs))
) = Flat((xs: List[T]) => xs flatMap f.fn)
This satisfies the implicit parameter required by recFlatten, it also takes another implicit paramater. Most crucially:
recFlattenFn can act as its own implicit parameter
it returns a Flat[List[X], X], so recFlattenFn will only be implicitly resolved as a Flat[T,U] if T is a List
the implicit f can fallback to a default value if implicit resolution fails (i.e. T is NOT a List)
Perhaps this is best understood in the context of one of the examples:
recFlatten(List(List(1, 2, 3), List(4, 5)))
The type T is inferred as List[List[Int]]
implicit lookup is attempted for a `Flat[List[List[Int]], U]
this is matched by a recursively defined recFlattenFn
Broadly speaking:
recFlattenFn[List[List[Int]], U] ( f =
recFlattenFn[List[Int], U] ( f =
Flat[Int,U]((xs: T) => List(xs)) //default value
)
)
Note that recFlattenFn will only match an implicit search for a Flat[List[X], X] and the type params [Int,_] fail this match because Int is not a List. This is what triggers the fallback to the default value.
Type inference also works backwards up that structure, resolving the U param at each level of recursion:
recFlattenFn[List[List[Int]], Int] ( f =
recFlattenFn[List[Int], Int] ( f =
Flat[Int,Int]((xs: T) => List(xs)) //default value
)
)
Which is just a nesting of Flat instances, each one (except the innermost) performing a flatMap operation to unroll one level of the nested List structure. The innermost Flat simply wraps all the individual elements back up in a single List.
Q.E.D.
May be a good solution is to try to look at how the types are infered. To avoid ambiguity, let us rename the generics:
case class Flat[T, U](fn : T => List[U])
implicit def recFlattenFn[T2, U2](implicit f : Flat[T2, U2] =
Flat((l : T2) => List(l))) =
Flat((l : List[T2]) => l.flatMap(f.fn))
def recFlatten[T3, U3](l : List[T3])(implicit f : Flat[List[T3], U3]) = f.fn(l)
In the first case, res0, the type of T3 is Int you cannot infer yet the type of U3, but you know that you will need a Flat[List[Int, U3]] object that will be provided implicitly. There is only one "implicit candidate": the result of the recFlattenFn function and its type is Flat[List[T2], List[U2]]. Thus T2 = Int and U2 = U3 (that we still need to infer).
Now, if we weant to be able to use recFlatten we must provide it a parameter f. Here is the trick. You can either use an implicit of type Flat[Int, U2] or the default value of type Int => List[Int]. Let us look about the available implicits. As explained before recFlattenFn can provide a Flat[List[T2], U2] (for a new T2 and U2) object. It does not fit the expected signature of fat this point. Thus, no implicit are a good candidate here and we must use the default argument. As the type of the default argument is Int => List[Int], U2and U3 are Int and there we go.
Hope that this long prose will help. I leave you with the resolution of res1 and res2.
I'm having trouble mapping a function that takes an optional parameter. I get the same type error as I would if the parameter were not optional. Here's a simple illustration:
scala> def multiple(m: Int, n: Int = 2) = m * n
multiple: (m: Int,n: Int)Int
scala> multiple(5)
res0: Int = 10
scala> multiple(5, 7)
res1: Int = 35
scala> (1 to 10).map(multiple)
<console>:7: error: type mismatch;
found : (Int, Int) => Int
required: (Int) => ?
(1 to 10).map(multiple)
Here's one way to make it work, but it requires repeating the default argument, which is a maintenance nightmare:
scala> (1 to 5).map { n => multiple(n, 2) }
res6: scala.collection.immutable.IndexedSeq[Int] = Vector(2, 4, 6, 8, 10)
Is there a better way to do it? More generally, why does a function with an optional parameter seem to have the same type as it would if the parameter was not optional? What is the actual type of multiple?
This seems to work:
(1 to 10).map(multiple(_))
//res0: scala.collection.immutable.IndexedSeq[Int] = Vector(2, 4, 6, 8, 10, 12, 14, 16, 18, 20)
When used in a situation expecting a function, Scala will "lift" a method to a FunctionN[T1,...,R].
In this situation, because multiple takes 2 parameters, it is lifted effectively as:
(1 to 10).map(new Function2[Int,Int,Int]{ def apply(v1: Int, v2: Int) = multiple(v1, v2) })
Even though the original method has a default argument, FunctionN objects do not. The type error should now be clear here. When multiple(_) is used, this is a call to multiple with a single argument with the second defaulted and so is treated like:
(1 to 10).map(new Function1[Int,Int]{ def apply(v1: Int) = multiple(v1) })
This type checks ok as others have shown.
Note that (multiple _ ) is not the same as multiple(_). The former represents multiple with all arguments wild carded and so is a Function2, whereas the latter is applying multiple to a single wild card argument, causing the other argument to be defaulted at that point, and so is a Function1.
Defaults are implemented at compile time by introducing a new method which returns the default value. Where the defaulted method is called, if arguments are missing, the compiler will add the necessary calls to the extra methods for the default parameters before adding the call to the method itself. This means that the method itself is compiled to code which itself has no knowledge of default parameters. To see this, compile the following sample class:
class Defaults {
def m(a: Int, b: Int = 3) = a * b
def a = m(1)
def b = m(1, 2)
}
then run: javap -c Defaults
For being able to write
scala> (1 to 10).map(multiple)
you can pass a partially applied function
def multiple(m: Int, n: Int) = m * n
val mul2 = multiple(_: Int, 2)
(1 to 10) map mul2
Here's one way to make it work, but it
requires repeating the default
argument, which is a maintenance
nightmare:
Btw this works too:
scala> (1 to 5).map { n => multiple(n) }
res0: scala.collection.immutable.IndexedSeq[Int] = Vector(2, 4, 6, 8, 10)
So you don't need to repeat the default argument either ;) [Scala 2.9.0.RC1]