簡體   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