I wrote a quite strange method in Scala.
def mystery(p: Int => String => Boolean): Int = ???
And now I cannot figure out what implementation and parameter value it should have.
So what is the simplest implementation this method can have? And what is the value we can pass to it?
My try:
def mystery(p: Int => String => Boolean): Int = {
val m = (x1: Int) => p(x1)
val n = (x2: String) => m(_)(x2)
val k = (x3: Boolean) => p(_)(_)(x3)
if (k) 1 else 0
}
How about this? p is a function, so to use it you need to pass it parameters. The parameters are curried, and the function is equivalent to Int => (String => Boolean). You give it an Int first, and it returns a function String => Boolean. So you give that a String, and it returns a Boolean.
def mystery(p: Int => String => Boolean): Int = {
val a = p(1)
val b = a("2")
if(b) 1 else 0
}
val f: Int => String => Boolean = (i: Int) => (s: String) => i.toString == s
mystery(f)
In your version, m, n, and k are all defined as functions. So, for example, when you say if (k) it doesn't make sense because if takes a Boolean, but you're giving it a function.
Related
What is the logical reason that the first form works and not the second?
scala> val d = (a: Int, b: Int) => a + b
d: (Int, Int) => Int = <function2>
scala> val d = (a: Int)(b: Int) => a + b
<console>:1: 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) => ... }
val d=(a:Int)(b:Int)=>a+b
Because multiple parameter lists aren't allowed on function declarations. If you want to curry a function, you do:
scala> val d: Int => Int => Int = a => b => a + b
d: Int => (Int => Int) = $$Lambda$1106/512934838#6ef4cbe1
scala> val f = d(3)
f: Int => Int = $$Lambda$1109/1933965693#7e2c6702
scala> f(4)
res6: Int = 7
You can also create a single parameter list and partially apply it:
scala> val d = (a: Int, b: Int) => a + b
d: (Int, Int) => Int = $$Lambda$1064/586164630#7c8874ef
scala> d(4, _: Int)
res2: Int => Int = $$Lambda$1079/2135563436#4a1a412e
We partially applied d with 4, and we got back a function, Int => Int, which means when we supply the next argument, we'll get the result:
scala> res2(3)
res3: Int = 7
We can also create a named method, and use eta-expansion to create a curried function out of it:
scala> def add(i: Int)(j: Int): Int = i + j
add: (i: Int)(j: Int)Int
scala> val curriedAdd = add _
curriedAdd: Int => (Int => Int) = $$Lambda$1115/287609100#f849027
scala> val onlyOneArgumentLeft = curriedAdd(1)
onlyOneArgumentLeft: Int => Int = $$Lambda$1116/1700143613#77e9dca8
scala> onlyOneArgumentLeft(2)
res8: Int = 3
Function currying is possible.
val curryFunc = (a: Int) => (b: Int) => a + b
curryFunc now has the type Int => (Int => Int)
Is it possible to do match-case over functions?
I want to define a behavior for different types of functions. Say I have the following possibilities:
f: T => Int
f: T => String
f: T => Lis[Int]
f: T => Boolean
f: T => Double
...
and for each of these options I have a function; for example for Int output:
def doThisForInt(f: T => Int) = { ... }
and this for Boolean output:
`
def doThisForBoolean(f: T => Boolean) = { ... }
So now suppose a function definition is given: val f = (input: T) => true. We should choose the corresponding case to f: T => Boolean.
Note that all these functions differ in the output type. Alternatively, given f can I get the output type of this function?
TypeTags are what you are looking for:
import scala.reflect.runtime.universe._
def doThisForInt(f: T => Int) = ???
def printType[R: TypeTag](f: T => R) = typeOf[R] match {
case t if t =:= typeOf[Int] =>
val toInt: (T) => Int = f.asInstanceOf[T => Int]
doThisForInt(toInt)
case t if t =:= typeOf[Double] =>
// ...
case t if t =:= typeOf[List[Int]] =>
// ...
}
printType((x: T) => 1) // int
printType((x: T) => 2.0) // double
printType((x: T) => List(2)) // list
As you can see, it is possible, but not very elegant and against good practices.
Chains of instanceOf checks can often be replaced with virtual methods (see the example) and the result type of function can possibly be a type parameter. It's hard to give more advice without knowing more context for your use case.
In Scala, defining a function whose parameter is called by name is like this:
def f(x: => R)
I think => R means the a function whose parameters are empty and return value type is R. But when I pass a function whose type is not => R into f, such as R => R, I find it still works. The example is like this:
scala> def foo(code: => Int) {
| println(code)
| }
foo: (code: => Int)Unit
scala> val bar: () => Int = () => 1
bar: () => Int = <function0>
scala> foo(bar())
1
scala> val bar1: Int => Int = myInt => 2
bar1: Int => Int = <function1>
scala> foo(bar1(2))
2
Could anyone can explain it?
The x: => R in the function definition doesn't stand for function without parameters which returns R, but it means an expression which, when evaluated, returns a value of type R without specifying anything else about the expression itself.
Im trying to write a function using currying to compute a Collatz series... But im getting lost when trying to write the parameters for construct6(...)
def c: Int => Int = construct6(isEven)(dec, inc)
//DONT KNOW WHAT TO DO HERE
def construct6: ((Int => Boolean) => (Int => Int, Int => Int)) => (i => (e, o)) = {
if (i(n)) e(n) else o(n)
}
def isEven: (Int) => (Boolean) = (a) => (a % 2 == 0)
def dec: (Int) => (Int) = (a) => (a / 2)
def inc: (Int) => (Int) = (a) => (a * 3 + 1)
You're construct6 function MUST take a Int n. Here is the function curried 3 times...
def construct6(i: Int => Boolean)(e: Int => Int, o: Int => Int)( n: Int): Int =
if (i(n)) e(n) else o(n)
When dealing with problems like this it is always important to look at the type signatures and see that they match up. Notice that construct6 MUST return an Int. We can doing some functional magic to make a function with a type signature to match Int => Int by doing this:
val c: Int => Int = construct6(isEven)(dec, inc)(_: Int)
We are partially applying the function you want for i, e, o, and leaving n as a variable.
Given:
def isEven: (Int) => (Boolean) = (a) => (a % 2 == 0)
def dec: (Int) => (Int) = (a) => (a / 2)
def inc: (Int) => (Int) = (a) => (a * 3 + 1)
you are still missing the n parameter to construct6 (as Andrew Cassidy says). Since you need to curry its parameters, it's more readable if you define construct6 like this (but it's basically the same definition you gave, I just added the n:Int at the end):
def construct6 (i:Int => Boolean)(e:(Int => Int)) (o:(Int => Int))(n:Int)
= if (i(n)) e(n) else o(n)
you can now define c as a Int=>Int by leaving out the last parameter n to construct6. In the REPL:
scala> def c: Int => Int = construct6(isEven)(dec)(inc)
c: Int => Int
scala> c(8)
res0: Int = 4
which I believe is what you were trying to do.
If you want to infer c's type instead of specifying it as a Int => Int explicitly) you will have to use the omnipresent _ to confirm to Scala that you're not just leaving out anything by mistake:
scala> def c2= construct6(isEven)(dec)(inc) _
c2: Int => Int
scala> c2(8)
res1: Int = 4
Is it possible to do something like the following?
def takeCurriedFnAsArg(f: (Int)(implicit MyClass) => Result)
Yes, it is possible.
When you have the second curried parameter marked as implicit, the function seems to be not of type
Int => (MyClass => Result) => ResultOfFunction
which it would be if the curried higher order function parameter was a regular parameter; instead, it looks like this:
Int => ResultOfFunction
Here's a quick example:
scala> def curriedFn(i : Int)(implicit func : String => Int) : Boolean = (i + func("test!")) % 2 == 0
curriedFn: (i: Int)(implicit func: String => Int)Boolean
scala> implicit val fn : String => Int = s => s.length
fn: String => Int = <function1>
scala> curriedFn _
res4: Int => Boolean = <function1>
As you can see, the implicit parameter got 'eliminated'. Why and how? That's a question for someone more knowledgeable than me. If I had to guess, I'd say the compiler directly substitutes the parameter with the implicit value, but that might very well be false.
Anyway, digressions aside, here's an example very relevant to your situation:
scala> def foo(func : Int => Boolean) = if(func(3)) "True!" else "False!"
foo: (func: Int => Boolean)String
scala> foo(curriedFn)
res2: String = True!
Now if the second function parameter wasn't implicit:
scala> def curriedNonImplicit(i : Int)(fn : String => Int) : Boolean = (i + fn("test!")) % 2 == 0
curriedNonImplicit: (i: Int)(fn: String => Int)Boolean
scala> curriedNonImplicit _
res5: Int => ((String => Int) => Boolean) = <function1>
As you can see, the type of the function is a bit different. That means that the solution will look different too:
scala> def baz(func : Int => (String => Int) => Boolean) = if(func(3)(s => s.length)) "True!" else "False!"
baz: (func: Int => ((String => Int) => Boolean))String
scala> baz(curriedNonImplicit)
res6: String = True!
You have to specify the function directly inside the method, as it wasn't implicitly provided before.