IM trying to understand the below high order functions in Scala but need some clarifications on the parameters of the functions.
Questions:-
What does the Int => String in the apply function mean?
v: Int indicates that the parameter v is of type Int.
What does the [A](x: A) mean in layout function?
object Demo {
def main(args: Array[String]) {
println( apply( layout, 10) )
}
def apply(f: Int => String, v: Int) = f(v)
def layout[A](x: A) = "[" + x.toString() + "]"
}
f: Int => String means that f is a function with one argument of type Int and with a return type String
def layout[A](x: A) means that parameter x is of type A, which can be of any type. Here are a couple of examples on how to invoke layout:
layout[String]("abc") //returns "[abc]"
layout[Int](123) //returns "[123]"
When main runs it invokes apply with the layout function and the argument 10. This will output "[10]"
The syntax of Int => String means passing a function that accepts Int and returns String.
Here is a useful example for passing function:
case class Person(name: String, lastName: String)
val person = Person("Johnny", "Cage")
def updateName(name: String) = {
updatePerson(_.copy(name = name))
}
def updateLastName(lastName: String) {
updatePerson(_.copy(lastName = lastName))
}
private def updatePerson(transformer: Person => Person): Unit = {
transformer(person)
}
Note how each update function passes the copy constructor.
Related
I've backed myself into an interesting corner while designing a higher order typed interface.
I want to do something like this
trait SomeTrait {
def higherOrder(f: (Int, A) => List[A]): String
}
object SomeImple extends SomeTrait {
def higherOrder(f: (Int, A) => List[A]): String = {
f(3, "HI").mkString(", ") + f(3, 7).mkString(", ")
}
}
I want to specify that a function takes another higher order function as input that works for any type (in this case A). For instance:
def someFun[A](n: Int, a: A): List[A] =
if (n <= 0) {
List.empty
} else {
a :: (someFun(n - 1, a))
}
However If a add a type parameter to the higherOrder that means the function f can only be used at one type. Is there a way to take parametric functions as inputs without overly constraining them?
You can't parameterize a function like that, but you can parameterize a method:
trait SomeTrait {
def higherOrder(fn: {def apply[A](n: Int, a: A): List[A]}): String
}
object SomeImple extends SomeTrait {
def higherOrder(f: {def apply[A](n: Int, a: A): List[A]}): String = {
f(3, "HI").mkString(", ") + f(3, 7).mkString(", ")
}
}
object someFun {
def apply [A] (n: Int, a: A): List[A] = {
if (n <= 0) {
List.empty
} else {
a :: (someFun(n - 1, a))
}
}
}
Using a structural type (or you can create a trait that can be implemented by the type holding the method), you can request the method take a type param.
Unfortunately, you have to wrap it in an object (or some class) because a regular method can only be "lifted" to a Function and a Function's type parameters are fixed at definition time.
For reference: https://gist.github.com/jdegoes/97459c0045f373f4eaf126998d8f65dc#polymorphic-functions
What's wrong with passing type to your function? Solution:
object HighOrderFunction {
type MyFunction[T] = (Int, T) => List[T]
def main(args: Array[String]): Unit = {
val dupInt: MyFunction[Int] = (n, value) => {
List.fill(n)(value)
}
val dupString: MyFunction[String] = (n, value) => {
List.fill(n)(value)
}
val dupDouble: MyFunction[Double] = (n, value) => {
List.fill(n)(value)
}
execute(dupInt, 5, 1)
execute(dupString, 5, "*")
execute(dupDouble, 5, 3.14)
}
def execute[T](f: MyFunction[T], n: Int, t: T): Unit = {
println(f(n, t))
}
}
I have the following two test cases:
TEST CASE 1:
#Test
def testImplicit1(): Unit = {
class Person(val age: Int)
val func: Person => Int = p => p.age
implicit val x = func
val y = implicitly((p: Person) => Int)
println(func.hashCode())
println(x.hashCode())
println(y.hashCode())
}
x and func have the same hashcode, while y's hashcode is different with the other two.
TEST CASE 2:
#Test
def testImplicit2(): Unit = {
class Person(val age: Int)
implicit val p = new Person(10)
val p2 = implicitly[Person]
println(p.hashCode())
println(p2.hashCode())
}
p and p2 have the same hash code
I would ask why y's hashcode is different with func and x's in TEST CASE 1
implicitly is defined as:
def implicitly[T](implicit e: T): T = e
What you are doing in test case 1 is explicitly passing in the value (not the type) for argument e as ((p: Person) => Int) which is a function that takes a Person as argument and returns the object Int. Then implicitly just returns that same value back to you.
What you want is:
val y = implicitly[Person => Int]
Which will cause the scala compiler to fill in the argument value e with your implicit value x.
How to use the map method in the Iterable trait in the example below?
As I understand this method will return a function which I have to call to execute internal logic.
trait Container[E] {
def += (e: E): Unit
}
trait Iterable[E, C[X] <: Container[X]]
{
def iterator(): Iterator[E]
def build[F](): C[F]
def map[F](f : (E) => F) : C[F] = {
val res = build[F]()
val iter = iterator()
while (iter.hasNext) res += f(iter.next())
res
}
}
class Buffer[T] extends Container[T]
{
val list = scala.collection.mutable.ListBuffer.empty[T]
def Children = list
def += (e: T): Unit = list += e
}
class Range(val low: Int, val high: Int) extends Iterable[Int, Buffer] {
def iterator() = new Iterator[Int]
{
private var i = low
def hasNext = i <= high
def next() = { i += 1; i - 1 }
}
def build[F]() = new Buffer[F]
}
val range = new Range(1, 3)
var list = range.map[String](_)
The method in question has the following signature:
trait Iterable[E, C[X] <: Container[X]] {
def map[F](f : (E) => F) : C[F]
// ...
}
First, let's look at the type of f argument. The signature (E) => F says that f is a function which takes a single argument of type E and returns a value of type F. Any function (or method) with this signature can be passed to map() as argument. See also Scala documentation.
Another important thing to understand is that the map function is generic with type parameter F. Value for this type parameter can either be specified manually or inferred by the compiler from the argument passed to map:
new Range(1,2).map[String](_.toString) // F is String
// new Range(1,2).map[Int](_.toString) // F is Int, compilation will fail
val mapFunction: Int => String = _.toString
new Range(1,2).map(mapFunction) // mapFunction is a function from Int to String,
// the compiler infers F is String
Basically, e.g. with Range, you can pass to the map() function any function which takes a single Int parameter (because Range binds E to Int) and returns anything (except for Unit). A few more examples:
val r = Range(1,2)
val v1: Buffer[String] = r.map(_.toString)
val v2: Buffer[Int] = r.map(i => i + 1)
val v3: Buffer[Double] = r.map(Int.int2double)
val i: Int = 1
val v4: Buffer[Int] = r.map(i.max)
As you can see, map() returns type Buffer[F] because that's what Range binds to the C[X] type parameter.
As #vitalii noted, the question is not related to higher-kinded types. For more information about those, check out other questions or blogs.
new Range(2,5).map(_.toString)
MWE (obs.: I am avoiding to have to instantiate a class every call of c, this is why functions are desired):
object Main extends App {
def a(s:String, i:Int) ={
s + i * i //some complex op that yields String
}
def b(i:Int) ={
i / 3 //another complex op that yields Int
}
def c(f: Any => Any) = {
val L = List(1,2,3,4) //list of complex elements
L map f //apply f within some complex loop
}
println(c(a))
/*
scala: type mismatch;
found : (String, Int) => String
required: Any => Any
println(c(a))
^
*/
println(c(b))
/*
scala: type mismatch;
found : Int => Int
required: Any => Any
println(c(b))
^
*/
}
Maybe an equivalent question would be "Is there some kind of function inheritance?",
like
def f
def fa(i: Int):String extends f
def fb(s: String):Int extends f
What you're trying to do isn't type-safe, since if it were you could pass a String to a function which takes an Int parameter:
e.g.
def c(f: Any => Any) = {
val L = List("a", "b", "c")
L map f
}
c(a)
However you can take a function of type Int => Any, since it is safe to assign a more derived type to Any.
def c(f: Int => Any) = {
val l = List(1,2,3,4)
l.map(f)
}
This is now safe:
val bList: List[Any] = c(b)
You still can't pass a to c however, since it requires two arguments instead of one. You can partially apply the first String argument and pass that:
val cList = c(a("SomeString", _:Int))
If you find yourself using Any,
you are probably doing something wrong, and
you most likely need generics.
In your case
def c[X,Y](f: X => Y) = { ... }
would probably do the trick, depending on what you have inside that complex loop.
Running a Squeryl call for some data that pulls from multiple locations, but for some reason it returns as a unit. How do I get it to return as an Iterable?
Below is pulling of the data:
/**
* gets a stream for a particular user
*/
def getUserStream(userId:Long) {
User.teamIds(userId).toList.map( (team) =>
Stream.findByTeam(team,0,5).map( (stream) =>
List(stream)
).flatten
).flatten.sortBy(_.id)
}
And then outputting the data, where results returns as Unit:
Stream.getUserStream(userId) match {
case results => {
Ok( generate(results.map( (stream) => Map(
"id" -> stream.id,
"model" -> stream.model,
"time" -> stream.time,
"content" -> stream.content
))
) ).as("application/json")
}
case _ => Ok("")
}
My initial guess is one function could return as a None, but wouldn't it just return an empty list?
You missing the equal sign before you def getUserStream(userId:Long) method body.
def func(x: Int) { x + 1 } // This will return Unit
def func(x: Int) = { x + 1 } // This will return a Int
To add a little bit that may be useful, saying def f(x: Int) {}
Is the equivalent of saying def f(x: Int): Unit = {}
If you do not declare the return type (e.g. def f(x: Int) = {}) the type will be inferred from your method body.
A technique to guarantee that you are returning a certain type is to declare it explicitly. This is something you would do when you want to export a public interface with a certain signature. This is important because if you let the type inferencer do all the work it may expose an abstraction that is more general than you want.
def f(x: Int): List[User] = {} // This will not compile.