In haskell I can write a function f where
f :: Set a -> Set a -> Set a
and if I take two sets, s1 & s2 of type Set Int, and do f s1 s2 it would produce something of type Set Int.
In scala however, I cannot write this, because A is some fixed type, which conflicts with
Long.
val x = Set(3L)
val y = Set(4L)
def foo[A](f: (Set[A], Set [A]) => Set [A]) = {
f(x,y)
}
What I really want though is def foo[forall A. A] .... How can I write this?
Edit The motivation is that I'm retrieving the data (x & y) from one source, and the method to call on them from another source. x & y are just some sets containing anything, but known to be the same type.
If I have some properly polymorphic function, I could just pass the x&y in, and intersection (or whatever) would work fine because intersection doesn't care what's in the sets, only that they're ordered. Perhaps I've gone forgotten how to do this in non haskell like ways...
In Scala and in Haskell type of f will be similar (up to an isomorphism):
f :: forall a. Set a -> Set a -> Set a
def f[A]: (Set[A], Set[A]) => Set[A]
Generic type parameters in Scala work exactly in the same way as type variables in Haskell. So I'm not sure why you say that in Scala it is impossible - it is not only possible but it even looks very similar. You can call f with arbitrary sets as arguments, just like you'd do it in Haskell:
f[Int](Set(1, 2), Set(3, 4))
The difference starts when you want to pass a polymorphic function into another function which will be able to use it with arbitrary type. In Haskell it requires higher-rank polymorphism:
foo :: (forall a. Set a -> Set a -> Set a) -> Whatever
foo f = toWhatever $ f (makeSet [1, 2, 3]) (makeSet [4, 5, 6]) // you get the idea
Scala does not have direct equivalent for this in its type system. You need to do a special trick to encode required relationship between types. First, define an additional trait:
trait PolyFunction2[F[_], G[_], H[_]] {
def apply[A](f: F[A], g: G[A]): H[A]
}
Then you need to extend this trait to define polymorphic functions:
def f = new PolyFunction2[Set, Set, Set] {
def apply[A](f: Set[A], g: Set[A]): Set[A] = f ++ g
}
And you need to use this trait to define type parameters:
def foo(f: PolyFunction2[Set, Set, Set]): (Set[Int], Set[String]) =
(f(Set(1, 2), Set(3, 4)), f(Set("a"), Set("b")))
scala> foo(f)
res1: (Set[Int], Set[String]) = (Set(1, 2, 3, 4),Set(a, b))
Of course, this is an ad-hoc implementation, so you better use Shapeless as it is more general.
Here's a polymorphic function that computes the intersection of two sets of any type, using shapeless
import shapeless._
import shapeless.poly._
object intersect extends Poly2 {
implicit def caseSet[A] = at[Set[A], Set[A]] { case (set1, set2) => set1 & set2 }
}
f(Set(3L, 4L), Set(4L, 5L)) // Set(4)
f(Set("foo", "bar", "baz"), Set("bar", "baz", "faz")) // Set("bar", "baz")
Then you can define a method taking any polymorphic function that can operate on two Sets:
def foo[A](a: Set[A], b: Set[A], f: Poly2)(
implicit c: Case2[f.type, Set[A], Set[A]]
) = f(a, b)
f(Set(3L, 4L), Set(4L, 5L), intersect) // Set(4)
f(Set("foo", "bar", "baz"), Set("bar", "baz", "faz"), intersect) // Set("bar", "baz")
That being said, the above is neat, but probably overkill in your case. In pure vanilla scala, you could instead do
def foo[A](a: Set[A], b: Set[A])(f: Function2[Set[A], Set[A], Set[A]]) = f(a, b)
foo(Set(1L, 2L), Set(2L, 3L)){ case (s1, s2) => s1 & s2 } // Set(2)
Related
We have Option which is an Iterable over 0 or 1 elements.
I would like to have such a thing with two elements. The best I have is
Array(foo, bar).map{...}, while what I would like is:
(foo, bar).map{...}
(such that Scala recognized there are two elements in the Iterable).
Does such a construction exist in the standard library?
EDIT: another solution is to create a map method:
def map(a:Foo) = {...}
val (mappedFoo, mappedBar) = (map(foo), map(bar))
If all you want to do is map on tuples of the same type, a simple version is:
implicit class DupleOps[T](t: (T,T)) {
def map[B](f : T => B) = (f(t._1), f(t._2))
}
Then you can do the following:
val t = (0,1)
val (x,y) = t.map( _ +1) // x = 1, y = 2
There's no specific type in the scala standard library for mapping over exactly 2 elements.
I can suggest you the following thing (I suppose foo and bar has the same type T):
(foo, bar) // -> Tuple2[T,T]
.productIterator // -> Iterator[Any]
.map(_.asInstanceOf[T]) // -> Iterator[T]
.map(x => // some works)
No, it doesn't.
You could
Make one yourself.
Write an implicit conversion from 2-tuples to a Seq of the common supertype. But this won't yield 2-tuples from operations.
object TupleOps {
implicit def tupleToSeq[A <: C, B <: C](tuple: (A, B)): Seq[C] = Seq(tuple._1,tuple._2)
}
import TupleOps._
(0, 1).map(_ + 1)
Use HLists from shapeless. These provide operations on heterogenous lists, whereas you (probably?) have a homogeneous list, but it should work.
I have a function in a context, (in a Maybe / Option) and I want to pass it a value and get back the return value, directly out of the context.
Let's take an example in Scala :
scala> Some((x:Int) => x * x)
res0: Some[Int => Int] = Some(<function1>)
Of course, I can do
res0.map(_(5))
to execute the function, but the result is wrapped in the context.
Ok, I could do :
res0.map(_(5)).getOrElse(...)
but I'm copy/pasting this everywhere in my code (I have a lot of functions wrapped in Option, or worst, in Either...).
I need a better form, something like :
res0.applyOrElse(5, ...)
Does this concept of 'applying a function in a concept to a value and immediatly returning the result out of the context' exists in FP with a specific name (I'm lost in all those Functor, Monad and Applicatives...) ?
You can use andThen to move the default from the place where you call the function to the place where you define it:
val foo: String => Option[Int] = s => Some(s.size)
val bar: String => Int = foo.andThen(_.getOrElse(100))
This only works for Function1, but if you want a more generic version, Scalaz provides functor instances for FunctionN:
import scalaz._, Scalaz._
val foo: (String, Int) => Option[Int] = (s, i) => Some(s.size + i)
val bar: (String, Int) => Int = foo.map(_.getOrElse(100))
This also works for Function1—just replace andThen above with map.
More generally, as I mention above, this looks a little like unliftId on Kleisli, which takes a wrapped function A => F[B] and collapses the F using a comonad instance for F. If you wanted something that worked generically for Option, Either[E, ?], etc., you could write something similar that would take a Optional instance for F and a default value.
You could write something like applyOrElse using Option.fold.
fold[B](ifEmpty: ⇒ B)(f: (A) ⇒ B): B
val squared = Some((x:Int) => x * x)
squared.fold {
// or else = ifEmpty
math.pow(5, 2).toInt
}{
// execute function
_(5)
}
Using Travis Browns recent answer on another question, I was able to puzzle together the following applyOrElse function. It depends on Shapeless and you need to pass the arguments as an HList so it might not be exactly what you want.
def applyOrElse[F, I <: HList, O](
optionFun: Option[F],
input: I,
orElse: => O
)(implicit
ftp: FnToProduct.Aux[F, I => O]
): O = optionFun.fold(orElse)(f => ftp(f)(input))
Which can be used as :
val squared = Some((x:Int) => x * x)
applyOrElse(squared, 2 :: HNil, 10)
// res0: Int = 4
applyOrElse(None, 2 :: HNil, 10)
// res1: Int = 10
val concat = Some((a: String, b: String) => s"$a $b")
applyOrElse(concat, "hello" :: "world" :: HNil, "not" + "executed")
// res2: String = hello world
The getOrElse is most logical way to do it. In regards to copy/pasting it all over the place - you might not be dividing your logic up on the best way. Generally, you want to defer resolving your Options (or Futures/etc) in your code until the point you need to have it unwrapped. In this case, it seems more sensible that your function takes in an an Int and returns an Int, and you map your option where you need the result of that function.
Given this spinet of code in Scala:
val mapMerge : (Map[VertexId, Factor], Map[VertexId, Factor]) => Map[VertexId, Factor] = (d1, d2) => d1 ++ d2
That can be shortened to:
val mapMerge : (Map[VertexId, Factor], Map[VertexId, Factor]) => Map[VertexId, Factor] = _ ++ _
What actually the code does is renaming the operator ++ of Map[VertexId, Factor] and therefore: Is there a way to assign that operator to the variable? Like in this imaginary example:
val mapMerge : (Map[VertexId, Factor], Map[VertexId, Factor]) => Map[VertexId, Factor] = Map.++
And probably with type inference it would enough to write
val mapMerge = Map[VertexId,Factor].++
Thanks
Unfortunately, no, because the "operators" in Scala are instance methods — not functions from a typeclass, like in Haskell.
Whey you write _ ++ _, you are creating a new 2-argument function(lambda) with unnamed parameters. This is equivalent to (a, b) => a ++ b, which is in turn equivalent to (a, b) => a.++(b), but not to (a, b) => SomeClass.++(a, b).
You can emulate typeclasses by using implicit arguments (see "typeclasses in scala" presentation)
You can pass "operators" like functions — which are not really operators. And you can have operators which look the same. See this example:
object Main {
trait Concat[A] { def ++ (x: A, y: A): A }
implicit object IntConcat extends Concat[Int] {
override def ++ (x: Int, y: Int): Int = (x.toString + y.toString).toInt
}
implicit class ConcatOperators[A: Concat](x: A) {
def ++ (y: A) = implicitly[Concat[A]].++(x, y)
}
def main(args: Array[String]): Unit = {
val a = 1234
val b = 765
val c = a ++ b // Instance method from ConcatOperators — can be used with infix notation like other built-in "operators"
println(c)
val d = highOrderTest(a, b)(IntConcat.++) // 2-argument method from the typeclass instance
println(d)
// both calls to println print "1234765"
}
def highOrderTest[A](x: A, y: A)(fun: (A, A) => A) = fun(x, y)
}
Here we define Concat typeclass and create an implementation for Int and we use operator-like name for the method in typeclass.
Because you can implement a typeclass for any type, you can use such trick with any type — but that would require writing quite some supporting code, and sometimes it is not worth the result.
Suppose I have a type class Graph[G,V] which states that an object of type G is also a graph with vertices of type V.
Now I have an implicit that lets me treat sets of pairs of type A as a graph with vertices of type A (not being able to express unconnected vertices...). I can use the implicit by importing the following object's scope.
object TupleSetGraph{
implicit def ts2graph[A]: Graph[Set[(A,A)],A] = new Graph[Set[(A,A)],A] {
def nodes(g: Set[(A, A)]): Set[A] = g flatMap (t => Set(t._1,t._2))
def adjacent(g: Set[(A, A)], n1: A, n2: A): Boolean = g.contains((n1,n2)) || g.contains((n2,n1))
}
}
Suppose I also want to be able to map the content of the vertices, thus being able to do the following:
(_: Set[(A,A)]).map((_: A => B)): Set[(B,B)]
But there is already a map defined on Set. How to deal with the problem that the same data structure can be seen as the same thing (something having a map function) in different ways?
Sketching a possible solution :
Put the map operation in an auxiliary trait
say GraphOps (that could be Graph itself, but map signature will probably be too complex for that)
case class GraphOps[G](data: G) { def map...}
Making it easy to get the GraphOps :
object Graph {
def apply[G](data: G) = GraphOps(data)
}
With that, the call will be
Graph(set).map(f)
apply could be made implicit, but I'm not sure I want to do that (and if I did, I'm not sure it would find map properly).
Variant. Have the graph in GraphOps
we can also do
case class GraphOps[G,V](data: G, graph: Graph[G,V])
and
object Graph {
def apply[G,V](data: G)(implicit graph: Graph[G,V]) = GraphOps(data, graph)
}
The good point of that is that vertex type V is available in GraphOps
Defining the map operation
The signature you want is complex, with Set[(A,A)] returning a Set[(B,B)], but other graph implementations returning something completely different. This is similar to what is done in the collection library.
We may introduce a trait CanMapGraph[From, Elem, To], akin to CanBuildFrom
trait CanMapGrap[FromGraph, FromElem, ToGraph, ToElem] {
def map(data: FromGraph, f: FromElem => ToElem): ToGraph
}
(probably you would change this to have more elementary operations than map, so that it may be used for different operations, as done with CanBuildFrom)
Then map would be
case class GraphOps[G](data: G) {
def map[A,B](f: A, B)(implicit ev: CanMapFrom[G, A, B, G2]) : G2 =
ev.map(data, f)
}
You can define
implicit def mapPairSetToPairSet[A, B] =
new CanMapGraph[Set[(A,A)], A, Set[(B,B)], B] {
def map(set: Set[(A,A)], f: A => B) = set.map{case (x, y) => (f(x), f(y))}
}
And then you do
val theGraph = Set("A" -> "B", "BB" -> "A", "B" -> "C", "C" -> "A")
Graph(theGraph).map(s: String -> s(0).toLower)
res1: Set[(Char, Char)] = Set((a,b), (b,a), (b,c), (c,a))
A problem with that is that the type of the vertices is not known in the first argument list, the one for f, so we have to be explicit with s: String.
With the alternative GraphOps, where we get the vertex type early, A is not a parameter of Map, but of GraphOps, so it is known from the start and does not need to be explicit in f. It you do it that way, you may want to pass the graph to method map in CanMapGraph.
With the first solution, it is still easy to give the graph to the CanMapGraph.
implicit def anyGraphToSet[G,V,W](implicit graph: Graph[G,V])
= new CanMapFrom[G, V, Set[(W,W)], W] {
def map(data: G, f: V => W) =
(for {
from <- graph.nodes(data)
to <- graph.nodes(data))
if graph.adjacent(data, from, to) }
yield (from, to)).toSet
}
val x: Set[(A, A)] = ...
(x: Graph[_, _]).map(...)
seems to be the best you can do if you want the names to be the same.
As you point out, that's not what you want. This should work better:
object Graph {
def map[G, V](graph: G)(f: V => V)(implicit instance: Graph[G, V]) = ...
}
val x: Set[(A, A)] = ...
Graph.map(x)(f)
// but note that the type of argument of f will often need to be explicit, because
// type inference only goes from left to right, and implicit arguments come last
Note that you can only let f to be V => V and not V => V1. Why? Imagine that you have
implicit g1: Graph[SomeType, Int], but not implicit g2: Graph[SomeType, String]. What could Graph.map(_: SomeType)((_: Int).toString) return then? This problem can be avoided by requiring G to be a parametrized type:
trait Graph[G[_]] {
def nodes[A](g: G[A]): Set[A]
def adjacent[A](g: G[A], n1: A, n2: A): Boolean
}
object TupleSetGraph{
type SetOfPairs[A] = Set[(A,A)]
implicit def ts2graph: Graph[SetOfPairs] = new Graph[SetOfPairs] {
def nodes[A](g: Set[(A, A)]): Set[A] = g flatMap (t => Set(t._1,t._2))
def adjacent[A](g: Set[(A, A)], n1: A, n2: A): Boolean = g.contains((n1,n2)) || g.contains((n2,n1))
}
}
then you have
object Graph {
def map[G[_], V, V1](graph: G[V])(f: V => V1)(implicit instance: Graph[G]) = ...
}
If you are using type classes, then you can do something like this:
implicitly[TypeClass].map(...)
If you are using view bounds, then Alexey's answer is correct:
(...: ViewBound).map(...)
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.