Suppose I have a few functions:
val f1: Int => String
val f2: (Int, Int) => String
val f3: (Int, Int, Int) => String
def fromList1(f: Int => String): List[Int] => Option[String] =
_ match {case x::_ => Some(f(x)); case _ => None}
def fromList2(f: (Int, Int) => String): List[Int] => Option[String] =
_ match {case x::y::_ => Some(f(x, y)); case _ => None}
Now I would like to write one generic fromList to work as follows:
val g1: List[Int] => String = fromList(f1) // as fromList1(f1)
val g2: List[Int] => String = fromList(f2) // as fromList2(f2)
Can I do that with shapeless ?
This may help:
import shapeless._
import syntax.std.traversable._
import shapeless.ops.traversable._
import syntax.std.function._
import ops.function._
def fromList[F, L <: HList, R](f: F)
(implicit fp: FnToProduct.Aux[F, L => R], tr: FromTraversable[L]) =
(p: List[Int]) => p.toHList[L] map f.toProduct
f.toProduct transforms regular function to function that takes HList as parameter - it requires FnToProduct implicit and actually just call it. FnToProduct.Aux is constructor (generated by macro) that creates FnToProduct from dunction F, hlist type HList and result type R. All of them are inferred from f parameter you passed.
Last one, toHList creates Some(HList) from regular List if it's possible, otherwise - None. It uses FromTraversable[L] implicit to do that, where L is already inferred from f. Shapeless2 is smart enough to recognize HList from Tuple (as there probably is implicit conversion).
Example:
scala> val f1: Int => String = _ => "a"
f1: Int => String = <function1>
scala> val f2: (Int, Int) => String = (_, _) => "a"
f2: (Int, Int) => String = <function2>
scala> val g1 = fromList(f1)
g1: List[Int] => Option[String] = <function1>
scala> g1(List(1))
res6: Option[String] = Some(a)
scala> val g2 = fromList(f2)
g2: List[Int] => Option[String] = <function1>
scala> g2(List(1, 2))
res7: Option[String] = Some(a)
scala> g2(List(1))
res8: Option[String] = None
Yes you can
import shapeless._
import shapeless.ops.traversable._
import syntax.std.traversable._
import ops.function._
def fromList[F, I <: HList, O](f: F)(implicit
ftp: FnToProduct.Aux[F, I => O],
ft: shapeless.ops.traversable.FromTraversable[I]): List[Int] => Option[O] =
{ x: List[Int] => x.toHList[I].map(ftp(f)) }
Explanation
We're using FnToProduct to transform any FunctionN to a Function1 that takes an HList as only argument.
So,
Int => String ----> Int :: HNil => String
(Int, Int) => String ----> Int :: Int :: HNil => String
...
Now that we abstracted over the arity of the input parameters for the function, we can simply convert the List[Int] to an HList that suits the transformed function's input.
In order to perform this conversion we need to a FromTraversable[I] in scope.
If everything succeeds we return and Option[O] where O is the return type of the function.
If the input List has the wrong shape, we simply fail returning None.
Usage
# val f1: Int => String = _.toString
f1: Int => String = <function1>
# val f2: (Int, Int) => String = (_, _).toString
f2: (Int, Int) => String = <function2>
# val fromList1 = fromList(f1)
fromList1: List[Int] => Option[String] = <function1>
# val fromList2 = fromList(f2)
fromList2: List[Int] => Option[String] = <function1>
# fromList1(List(1))
res22: Option[String] = Some(1)
# fromList2(List(1, 2))
res23: Option[String] = Some((1,2))
# fromList1(List())
res24: Option[String] = None
Related
I want to write a simple method that takes a function as a parameter and then executes it.
def exec(f: (a:Int, b:Int) => Boolean): Boolean = f(a,b)
I'm not sure what is wrong with the above, but I get the error:
<console>:1: error: ')' expected but ':' found.
def exec(f: (a:Int, b:Int) => Boolean): Boolean = f(a,b)
^ ^
| |
// These are supposed to be types, but a: Int and b: Int aren't types,
// they are identifiers with type ascriptions.
It should look a little more like:
def exec(f: (Int, Int) => Boolean): Boolean = f(a, b)
Now f is a function (Int, Int) => Boolean. But this doesn't compile, because a and b are not defined.
You either need to pass them in, or fix them to a value.
def exec(a: Int, b: Int)(f: (Int, Int) => Boolean): Boolean = f(a, b)
scala> exec(2, 3)(_ > _)
res1: Boolean = false
If you want to execute a function with parameters in your exec method you need to:
scala> def exec(f: => Unit) = {
| println("Exec:")
| f
| }
scala> def foo(f : (Int, Int)): Unit = println(f._1 + f._2)
scala> exec(foo((3, 4)))
Exec:
7
because foo((3, 4)) type is => Unit
Not quite an answer to your original question (and too big to be a comment), but if you're looking to write a tasteful, nice-looking execution operator and don't particularly like the syntax of the provided answers, perhaps something similar to scalaz's pipe operator (|>) might be what you're thinking of?
scala> // You could just get this from scalaz with import scalaz._ and import Scalaz._
scala> implicit class FancyExec[A](x: A){def |>[B](f: A => B) = f(x)}
scala> 5 |> (_ + 6)
res1: Int = 11
scala> (5, 4) |> ((_: Int) < (_: Int)).tupled
res2: Boolean = false
scala> val f = ((_: Int) < (_: Int)).tupled
f: ((Int, Int)) => Boolean = <function1>
scala> val g = ((_: Int) > (_: Int)).tupled
g: ((Int, Int)) => Boolean = <function1>
scala> List(f, g) map ((5, 4) |> _)
res3: List[Boolean] = List(false, true)
Suppose I have a few functions of type Int => Option[Int]:
def foo(n: Int): Int => Option[Int] = {x => if (x == n) none else x.some}
val f0 = foo(0)
val f1 = foo(1)
I can compose them with >=> as follows:
val composed: Int => Option[Int] = Kleisli(f0) >=> Kleisli(f1)
Suppose now I need to compose all functions from a list:
val fs: List[Int => Option[Int]] = List(0, 1, 2).map(n => foo(n))
I can do it with map and reduce:
val composed: Int => Option[Int] = fs.map(f => Kleisli(f)).reduce(_ >=> _)
Can it (the composed above) be simplified ?
If you want the composition monoid (as opposed to the "run each and sum the results" monoid), you'll have to use the Endomorphic wrapper:
import scalaz._, Scalaz._
val composed = fs.foldMap(Endomorphic.endoKleisli[Option, Int])
And then:
scala> composed.run(10)
res11: Option[Int] = Some(10)
The monoid for kleisli arrows only requires a monoid instance for the output type, while the composition monoid requires the input and output types to be the same, so it makes sense that the latter is only available via a wrapper.
[A] Kleisli[Option, A, A] is a Semigroup via Compose, so we can use foldMap1:
val composed: Int => Option[Int] = fs.foldMap1(f => Kleisli(f))
Interestingly this doesn't work, though if we pass the correct instance explicitly then it does:
scala> val gs = NonEmptyList(fs.head, fs.tail: _*)
gs: scalaz.NonEmptyList[Int => Option[Int]] = NonEmptyList(<function1>, <function1>, <function1>)
scala> gs.foldMap1(f => Kleisli(f))(Kleisli.kleisliCompose[Option].semigroup[Int])
res20: scalaz.Kleisli[Option,Int,Int] = Kleisli(<function1>)
scala> gs.foldMap1(f => Kleisli(f))(Kleisli.kleisliCompose[Option].semigroup[Int]).apply(1)
res21: Option[Int] = None
I'm not sure where the instance that seems to take priority is coming from.
When I'm matching value of case classes, such as:
sealed abstract class Op
case class UOp[T, K](f: T => K) extends Op
case class BOp[T, Z, K](f: (T, Z) => K) extends Op
like this:
def f(op: Op): Int =
op match
{
case BOp(g) => g(1,2)
case UOp(g) => g(0)
}
the compiler infers it as
val g: (Nothing, Nothing) => Any
val g: Nothing => Any
Why am I getting Nothing as the type? Is it because of JVM type erasure? Are there elegant ways to match functions against variables?
I came up with this "hackish" solution, maybe there are other ways or cleaner ways to do this still without relying on reflection.
Define a few partial functions which will handle various args:
scala> val f: PartialFunction[Any, String] = { case (x: Int, y: String) => y * x }
f: PartialFunction[Any,String] = <function1>
scala> val g: PartialFunction[Any, String] = { case x: Int => x.toString }
g: PartialFunction[Any,String] = <function1>
scala> def h: PartialFunction[Any, BigDecimal] = { case (a: Int, b: Double, c: Long) => BigDecimal(a) + b + c }
h: PartialFunction[Any,BigDecimal]
scala> val l: List[PartialFunction[Any, Any]] = f :: g :: h :: Nil
l: List[PartialFunction[Any,Any]] = List(<function1>, <function1>, <function1>)
Check which functions can handle different inputs:
scala> l.map(_.isDefinedAt(1))
res0: List[Boolean] = List(false, true, false)
scala> l.map(_.isDefinedAt((1, "one")))
res1: List[Boolean] = List(true, false, false)
Given input find and apply a function:
scala> def applyFunction(input: Any): Option[Any] = {
| l find (_.isDefinedAt(input)) map (_ (input))
| }
applyFunction: (input: Any)Option[Any]
scala> applyFunction(1)
res1: Option[Any] = Some(1)
scala> applyFunction((2, "one"))
res2: Option[Any] = Some(oneone)
scala> applyFunction("one")
res3: Option[Any] = None
scala> applyFunction(1, 1.1, 9L)
res10: Option[Any] = Some(11.1)
This looks quite type unsafe and there must be better ways to do this.
I think magnet pattern should handle this well in more typesafe manner.
As an example, I want to apply a function f: (Int,Int) => Int to two elements of type Option[Int]. My thoughts were something like (a,b).zipped.map(f), but this yields a List, and I want to get a new Option[Int] as result.
scala> def f(a:Int,b:Int) = a*b
f: (a: Int, b: Int)Int
scala> val x = Some(42)
x: Some[Int] = Some(42)
scala> val y:Option[Int] = None
y: Option[Int] = None
scala> (x,y).zipped.map(f)//I want None as a result here
res7: Iterable[Int] = List()
How can this be done without explicitly branching?
Just like many other operations in scala this can be done via for comprehension:
def f(a:Int,b:Int) = a*b
for (x <- maybeX; y <- maybeY) yield f(x, y)
As often is the case with this type of question, scalaz has some help:
scala> import scalaz._
import scalaz._
scala> import Scalaz._
import Scalaz._
scala> def f(a:Int,b:Int) = a*b
f: (a: Int, b: Int)Int
scala> val x = Some(42)
x: Some[Int] = Some(42)
scala> val y:Option[Int] = None
y: Option[Int] = None
scala> ^(x,y)(f)
res0: Option[Int] = None
scala> val x = 42.some
x: Option[Int] = Some(42)
scala> (x |#| y)(f)
res3: Option[Int] = None
Using om-nom-nom's idea, I can do something like this:
scala> def f(a:Int,b:Int) = a*b
f: (a: Int, b: Int)Int
scala> def lifted(f: (Int,Int) => Int) = (a:Option[Int],b:Option[Int]) => for(x<-a;y<-b) yield f(x,y)
lifted: (f: (Int, Int) => Int)(Option[Int], Option[Int]) => Option[Int]
scala> def liftedF = lifted(f)
liftedF: (Option[Int], Option[Int]) => Option[Int]
scala> val x = Some(42)
x: Some[Int] = Some(42)
scala> val y:Option[Int] = None
y: Option[Int] = None
scala> liftedF(x,x)
res0: Option[Int] = Some(1764)
scala> liftedF(x,y)
res2: Option[Int] = None
We can even generalize this...please cover your eyes:
def lift2[A, B, C](f: (A, B) => C): (Option[A], Option[B]) => Option[C] = (a: Option[A], b: Option[B]) =>
for (x <- a; y <- b) yield f(x, y)
I want to implicitly convert functions from A => B to List[A] => List[B].
I wrote the following implicit definition:
implicit def lift[A, B](f: A => B): List[A] => List[B] = ...
Unfortunately, when I write the following code, implicit aren't applied:
val plusOne: (List[Int]) => List[Int] = (x: Int) => (x + 1)
If I annotate the function with explicit time, it works fine.
Why? How can I fix it?
UPDATE. It seems that the problem is specific to anonymous functions. Compare:
#Test
def localLiftingGenerics {
implicit def anyPairToList[X, Y](x: (X, Y)): List[X] => List[Y] = throw new UnsupportedOperationException
val v: List[String] => List[Int] = ("abc", 239)
}
#Test
def localLiftingFuns {
implicit def fun2ListFun[X, Y](f: X => Y): List[X] => List[Y] = throw new UnsupportedOperationException
val v: List[String] => List[Int] = ((x: String) => x.length)
}
The first one is compiled well. The second one is marked as error
According to The Scala Language Specification / Expressions / Anonymous Functions (6.23):
If the expected type of the anonymous function is of the form
scala.Functionn[S1, …, Sn, R], the expected type of e is R ...
So, the result type of the function will be inferred as List[Int] unless you separate the function definition from the function value assignment (to get rid of the expected type):
val function = (x: Int) => (x + 1)
val plusOne: (List[Int]) => List[Int] = function
or specify the function type explicitly:
val plusOne: (List[Int]) => List[Int] = ((x: Int) => (x + 1)): Int => Int
(Scala 2.9.1-1 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_05)
A first observation: If you duplicate fun2ListFun and rename it to, e.g.,``fun2ListFun, you'll get
found : String => <error>
required: List[String] => List[Int]
Note that implicit conversions are not applicable because they are ambiguous:
both method fun2ListFun2 of type [X, Y](f: X => Y)List[X] => List[Y]
and method fun2ListFun of type [X, Y](f: X => Y)List[X] => List[Y]
are possible conversion functions from String => <error> to List[String] => List[Int]
val v: List[String] => List[Int] = ((x: String) => x.length)
It looks as if the compiler considers both implicits as applicable.
A second observation:
Splitting
val v: List[String] => List[Int] = ((x: String) => x.length) /* Error*/
into
val f = ((x: String) => x.length)
val v: List[String] => List[Int] = f /* Works */
makes the compiler happy.
The implicit conversion for the input value compiles. So we just have a problem for the output of the anonymous function
def localLiftingFuns {
implicit def fun2ListFun[X, Y](f: X => Y): List[X] => Y = throw new UnsupportedOperationException
val v: List[String] => Int = ((x: String) => x.length)
}
A possible fix using a second implicit conversion:
def localLiftingFuns {
implicit def fun2ListFun[X, Y](f: X => List[Y]): List[X] => List[Y] = throw new UnsupportedOperationException
implicit def type2ListType[X](x:X): List[X] = throw new UnsupportedOperationException
val v: List[String] => List[Int] = ((x: String) => x.length)
}
This version compiles.
Seems the compiler has hard time figuring what is going on with the type of the function. If you will give him a little help, it would work:
scala> implicit def lift[A,B](f: A => B) = (_:List[A]).map(f)
lift: [A, B](f: (A) => B)(List[A]) => List[B]
scala> val f: List[Int] => List[Int] = ((_:Int) + 1):(Int => Int)
f: (List[Int]) => List[Int] = <function1>