package com.myapp
object Test2 extends App {
trait Wrapper[C[_]] {
def aFunction[T,R](f: T => R): C[T] => C[R]
}
implicit object ListWrapper extends Wrapper[List] {
//returns a function: so this is a higher order function
override def aFunction[T,R](f: T => R): List[T] => List[R] = { l =>
println("taking T => R & returning List[T] => List[R]")
l.map(f)
}
}
// A function that returns an anonymous Object
// Anonymous class Test2$$anon$1 AnyRef is like java.lang.Object
private implicit def fnGenAnonymousObj[C[_], T](input: C[T]) = new { // or new AnyRef or new Object
//takes a function as an arg: So, this is a higher order function
def anotherFunction[R](f: T => R)(implicit wrap: Wrapper[C]): C[R] = {
println("In here first.......")
val aClosure: C[T] => C[R] = wrap.aFunction(f) // C[T] => C[R]
val result: C[R] = aClosure(input) // pass the list to the closure
result
}
}
//val result = fnGenAnonymousObj(List(1, 2, 3)).anotherFunction {x => x + 1}(ListWrapper) // without implicits
val result = List(1, 2, 3).anotherFunction {x => x + 1}
println(result)
//val result2 = fnGenAnonymousObj(List("Java", "Scala")).anotherFunction {x => x.length}(ListWrapper) // without implicits
val result2 = List("Java", "Scala").anotherFunction {x => x.length} // with implicits
println(result2)
}