2010-02-26 28 views
43

'地圖'保留了元素的數量,所以在Tuple上使用它似乎是明智的。在Scala元組上使用函數組合器?

我嘗試至今:

scala> (3,4).map(_*2)  
error: value map is not a member of (Int, Int) 
     (3,4).map(_*2) 
      ^
scala> (3,4).productIterator.map(_*2) 
error: value * is not a member of Any 
     (3,4).productIterator.map(_*2) 
           ^
scala> (3,4).productIterator.map(_.asInstanceOf[Int]*2) 
res4: Iterator[Int] = non-empty iterator 

scala> (3,4).productIterator.map(_.asInstanceOf[Int]*2).toList 
res5: List[Int] = List(6, 8) 

看起來蠻痛苦的......我還沒有開始嘗試將其轉換回一個元組。
我做錯了嗎?圖書館可以改進嗎?

+0

它看起來像你正在使用一個元組,你真的應該使用一個集合。考慮使用真正的集合類 - 元組不應該被用作一種集合。 – Jesper 2010-04-30 18:47:06

+1

@Jesper:我不同意:我可能只是簡單地將DRY'ly應用於相同的操作,並精確地應用於大小靜態已知的項目集合。 – 2014-03-08 05:16:11

回答

27

shapeless支持映射和經由中間HList表示摺疊元組,

樣品REPL會話,

scala> import shapeless._ ; import Tuples._ 
import shapeless._ 
import Tuples._ 

scala> object double extends (Int -> Int) (_*2) 
defined module double 

scala> (3, 4).hlisted.map(double).tupled 
res0: (Int, Int) = (6,8) 

當數組的元素是不同的類型,您可以與特定類型的情況下,多態函數映射的,

scala> object frob extends Poly1 { 
    | implicit def caseInt  = at[Int](_*2) 
    | implicit def caseString = at[String]("!"+_+"!") 
    | implicit def caseBoolean = at[Boolean](!_) 
    | } 
defined module frob 

scala> (23, "foo", false, "bar", 13).hlisted.map(frob).tupled 
res1: (Int, String, Boolean, String, Int) = (46,!foo!,true,!bar!,26) 

更新

至於無形2.0.0-M1映射在元組的直接支持。上面的例子現在看起來像這樣,

scala> import shapeless._, poly._, syntax.std.tuple._ 
import shapeless._ 
import poly._ 
import syntax.std.tuple._ 

scala> object double extends (Int -> Int) (_*2) 
defined module double 

scala> (3, 4) map double 
res0: (Int, Int) = (6,8) 

scala> object frob extends Poly1 { 
    | implicit def caseInt  = at[Int](_*2) 
    | implicit def caseString = at[String]("!"+_+"!") 
    | implicit def caseBoolean = at[Boolean](!_) 
    | } 
defined module frob 

scala> (23, "foo", false, "bar", 13) map frob 
res1: (Int, String, Boolean, String, Int) = (46,!foo!,true,!bar!,26) 
+0

這太棒了!我會將您的答案標記爲已接受,但我不知道在幾年後更改接受的答案是否可行。 – 2013-10-25 15:13:12

+2

你應該接受你認爲最好的答案。如果情況或您的意見隨着時間而改變,那麼我認爲相應地更新您的接受是合理的。 – 2013-10-27 12:21:54

+0

恕我直言,這個東西太抽象了。我的意思是,它需要導入3個完整的名稱空間(import xxxxx._),並且對於完整的泛型情況,它需要與元組中的項類型一樣多的額外含義。 它肯定取決於用例,但最有可能的是,簡單的,明確的代碼將更具可讀性而不會損失效率。 – 2016-04-25 13:03:40

35

一般來說,元組的元素類型不一樣,所以地圖沒有意義。您可以定義一個函數來處理的特殊情況下,雖然:

scala> def map[A, B](as: (A, A))(f: A => B) = 
    as match { case (a1, a2) => (f(a1), f(a2)) } 
map: [A,B](as: (A, A))(f: (A) => B)(B, B) 

scala> val p = (1, 2)  
p: (Int, Int) = (1,2) 

scala> map(p){ _ * 2 } 
res1: (Int, Int) = (2,4) 

您可以使用皮條客我的圖書館模式調用此爲p.map(_ * 2)

UPDATE

即使當類型的元件是不一樣的,Tuple2[A, B]Bifunctor,其可以與bimap操作進行映射。

scala> import scalaz._ 
import scalaz._ 

scala> import Scalaz._ 
import Scalaz._ 

scala> val f = (_: Int) * 2 
f: (Int) => Int = <function1> 

scala> val g = (_: String) * 2 
g: (String) => String = <function1> 

scala> f <-: (1, "1") :-> g 
res12: (Int, String) = (2,11) 

UPDATE 2

http://gist.github.com/454818

+0

爲了記錄,我正在將接受的答案從此更改爲關於無形狀庫的更近期回答,該形式庫在2010年不可用。 – 2013-10-28 12:40:35