Scala equivalent to 'forall a. Install a & # 8594; Install a & # 8594; Set a '

In haskell, I can write a function f where

f :: Set a -> Set a -> Set a

      

and if I take two sets, s1

and s2

type Set Int

, and do f s1 s2

, it produces something like Set Int

.

In scala, however, I cannot write this because A is some fixed type that conflicts with Long.

val x = Set(3L)
val y = Set(4L)

def foo[A](f: (Set[A], Set [A]) => Set [A]) = {
  f(x,y)
}

      

I really want to, but this def foo[forall A. A] ...

. How can I write this?

Edit. The motivation is that I extract the data ( x

and y

) from one source and method for a call from another source. x

and y

are just some sets containing something, but, as you know, of the same type.
If I have some valid polymorphic function, I can just pass x

& y

in, and the intersection (or whatever) will work fine, because the intersection doesn't care what's in the sets, just that they are ordered. Maybe I forgot how to do this in non haskell, how ways ...

+3


source to share


2 answers


In Scala and in Haskell, the type f

will be the same (up to 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 like type variables in Haskell. So I'm not sure why you are saying that this is not possible in Scala - not only is it possible, but it looks very similar. You can call f

with arbitrary sets as arguments, just like in Haskell:

f[Int](Set(1, 2), Set(3, 4))

      

The difference starts when you want to pass a polymorphic function to another function that can use it with an arbitrary type. Haskell 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 has no direct equivalent for this in its type system. You need to do a special trick to encode the required relationship between the types. First, define an additional characteristic:

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))

      

This is of course an ad-hoc implementation, so you are better off using Shapeless as it is more general.

+1


source


Here's a polymorphic function that calculates 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 that accepts any polymorphic function that can run on two Set

s:

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")

      




Having said that, the above is neat but probably overwhelming your case. In pure vanilla scala, you could 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)

      

0


source







All Articles