2010-02-26 4 views
43

'map'은 요소의 수를 유지하므로 터플에서 사용하면 합리적입니다.스칼라 튜플에서 기능 결합자를 사용 하시겠습니까?

내 시도까지 :

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

+1

@Jesper : 나는 동의하지 않는다 : 나는 단순히 같은 작업을 DRY'ly 적용하고 크기가 정적으로 알려진 항목의 모음에 합리적으로 적용하기를 원할 수도있다. –

답변

27

shapeless가 매핑 및 중간 HList 표현을 통해 튜플을 통해 폴딩을 지원 UPDATE,

샘플 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) 
012 튜플의 요소는 타입 별 사례와 다형성 기능을 매핑 할 수 있습니다 다른 종류의 수 있습니다 3,516,

, 튜플 이상 볼품 2.0.0-M1 매핑으로

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) 

업데이트

직접 지원됩니다. 위의 예제는 이제 다음과 같이 보입니다.

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

이것은 굉장합니다! 귀하의 답변을 수락 한 것으로 표시 하겠지만 몇 년 후에 승인 된 답변을 변경해도 괜찮은지 모르겠습니다. –

+2

당신은 가장 좋은 대답이라고 생각하는 것을 받아 들여야합니다. 상황 또는 귀하의 의견이 시간이 지남에 따라 변하면 귀하의 수락을 그에 맞게 업데이트하는 것이 합리적이라고 생각합니다. –

+0

IMHO,이 물건은 너무 추상적입니다. 즉, 3 개의 전체 네임 스페이스 (import xxxxx._)를 가져와야하며 전체적인 경우에는 튜플에있는 항목 유형만큼 추가 implicits가 필요합니다. 확실히 유스 케이스에 달려 있지만, 아마도 단순하고 명시적인 코드가 효율성을 잃지 않으면 서 더 읽기 쉬울 것입니다. –

35

일반적으로 튜플의 요소 유형은 동일하지 않으므로 map이 적합하지 않습니다. 당신은하지만, 특별한 경우를 처리하는 함수를 정의 할 수 있습니다 :

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]bimap 동작으로 매핑 될 수 Bifunctor이다.

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) 

2

http://gist.github.com/454818

+0

기록을 위해, 나는 받아 들여진 응답을 이것에서 2010 년에 다시 사용할 수 없었던 Shapeless 라이브러리에 대한 가장 최근의 대답으로 바꾸고 있습니다. –

관련 문제