繁体   English   中英

Scala相当于'forall a。 设置 - >设置 - >设置'

[英]Scala equivalent of 'forall a. Set a -> Set a -> Set a'

在haskell中我可以写一个函数f where

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

如果我采用两个集合,类型为Set Int s1s2 ,并且执行f s1 s2 ,它将生成Set Int类型的东西。

然而,在scala中,我不能写这个,因为A是一些固定类型,它与Long冲突。

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

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

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

编辑动机是我从一个源检索数据( xy ),以及从另一个源调用它们的方法。 xy只是包含任何内容的一些集合,但已知是相同的类型。
如果我有一些正确的多态函数,我可以只传递xy ,并且交集(或其他)可以正常工作,因为交集不关心集合中的内容,只是它们是有序的。 也许我已经忘记了如何以非类似的方式做到这一点......

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

f :: forall a. Set a -> Set a -> Set a
def f[A]: (Set[A], Set[A]) => Set[A]

Scala中的泛型类型参数的工作方式与Haskell中的类型变量完全相同。 所以我不确定你为什么说在Scala中这是不可能的 - 它不仅可能,而且看起来非常相似。 您可以使用任意集作为参数调用f ,就像在Haskell中执行它一样:

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

当你想将多态函数传递给另一个能够以任意类型使用它的函数时,差异就开始了。 在Haskell中,它需要更高级别的多态性:

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在其类型系统中没有与此直接等效。 你需要做一个特殊的技巧来编码类型之间所需的关系。 首先,定义一个额外的特征:

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,因为它更通用。

这是一个多态函数,它使用无形来计算任意类型的两个集合的交集

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

然后你可以定义一个方法,采用任何可以在两个Set上运行的多态函数:

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

话虽如此,上面说的很整洁,但在你的情况下可能有些过分。 在纯香草scala,你可以做

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)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM