Scala等效于';福尔a。设置a->;设置a->;设置一个';

Scala等效于';福尔a。设置a->;设置a->;设置一个';,scala,types,Scala,Types,在haskell中,我可以编写一个函数f,其中 f :: Set a -> Set a -> Set a 如果我取两组,类型为Set Int的s1和s2,然后对s1s2进行f,它会产生类型为Set Int的东西 但是,在scala中,我不能写这个,因为A是某种固定类型,与 长 但我真正想要的是def foo[forall A.A]…。我怎么写这个 编辑动机是我从一个源中检索数据(x&y),以及从另一个源调用它们的方法x&y只是一些包含任何内容的集合,但已知它们是相同类型的。 如果我

在haskell中,我可以编写一个函数f,其中

f :: Set a -> Set a -> Set a
如果我取两组,类型为
Set Int
s1
s2
,然后对s1s2进行
f,它会产生类型为
Set Int
的东西

但是,在scala中,我不能写这个,因为A是某种固定类型,与 长

但我真正想要的是
def foo[forall A.A]…
。我怎么写这个

编辑动机是我从一个源中检索数据(
x
&
y
),以及从另一个源调用它们的方法
x
&
y
只是一些包含任何内容的集合,但已知它们是相同类型的。

如果我有一些适当的多态函数,我可以将
x
&
y
传入,交集(或任何东西)可以正常工作,因为交集不关心集合中的内容,只关心它们的顺序。也许我忘记了如何用非haskell式的方法来实现这一点…

这里有一个多态函数,它使用

然后,您可以定义一个方法,该方法使用任何多态函数,该函数可以在两个
集合上操作:

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

也就是说,上面的内容很简洁,但在你的情况下可能有些过火了。在纯香草斯卡拉,你可以做

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)

在Scala和Haskell中,
f
的类型类似(直至同构):

f::对于所有a。设置a->设置a->设置a
def[A]:(Set[A],Set[A])=>Set[A]
Scala中的泛型类型参数的工作方式与Haskell中的类型变量完全相同。所以我不知道你为什么说在Scala中这是不可能的——这不仅是可能的,而且看起来非常相似。您可以使用任意集作为参数调用
f
,就像在Haskell中一样:

f[Int](Set(1, 2), Set(3, 4))
当您想将一个多态函数传递给另一个能够将其用于任意类型的函数时,这种差异就开始了。在Haskell中,它需要更高级别的多态性:

foo::(对于所有a.设置a->设置a->设置a)-->无论什么
foo f=toWhatever$f(makeSet[1,2,3])(makeSet[4,5,6])//你明白了
Scala在其类型系统中对此没有直接等价物。您需要做一个特殊的技巧来编码类型之间所需的关系。首先,定义一个额外的特征:

trait PolyFunction2[F[_], G[_], H[_]] {
  def apply[A](f: F[A], g: G[A]): H[A]
}
然后您需要扩展此特性以定义多态函数:

def f = new PolyFunction2[Set, Set, Set] {
  def apply[A](f: Set[A], g: Set[A]): Set[A] = f ++ g
}
您需要使用此特性来定义类型参数:

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

当然,这是一个特殊的实现,所以最好使用Shapeless,因为它更通用。

我不能100%确定,但我想说你不能这样做,我也不明白这有什么意义,如果您想要一个访问外部不可变变量的方法,您应该将
a
的类型硬编码为
Long
,因为它们实际上是不可变的。如果您想要一个执行某些转换的泛型方法,那么应该将变量传递给该方法。但可能我遗漏了一些东西。本文可能与此相关:如果您对一个简单的多态方法没有异议,您可以更改函数签名,以便:
def foo[a](s1:Set[a],s2:Set[a])(f:(Set[a],Set[a])=>Set[a]:Set[a]
def f = new PolyFunction2[Set, Set, Set] {
  def apply[A](f: Set[A], g: Set[A]): Set[A] = f ++ g
}
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))