2013-03-21 2 views
3

:왜 스칼 랙 유형 불일치가 Int를 기대합니까? 어젯밤 프로젝트를 진행하고,이 같은 일부 코드가 있었다

/* fixes warnings in 2.10 */ 
import scala.language.implicitConversions 

/* had some kind of case class with some members */ 
case class Wrapper[A](x: A) 

/* for convenience's sake */ 
implicit def aToWrapper[A](x: A) = Wrapper(x) 

/* had some kind of Seq */ 
val xs: List[Wrapper[String]] = List("hello", "world", "this", "is", "a", "test") 

을 그때 실수로 썼다 :

xs foldLeft("") { (a, x) => a + x } 

xsfoldLeft 사이 밖으로 .을 떠난.

문제의 유형이 좀 더 복잡하고 람다의 매개 변수 유형에 주석을달라고 요청했기 때문에 실수를 저지른 원인이라고 생각했습니다. 내가 오류 수신 된이 시점에서

xs foldLeft("") { (a: String, x: Wrapper[String]) => a + x } 

: :이 같은 뭔가 결국 분명히

<console>:13: error: type mismatch; 
found : (String, Wrapper[String]) => String 
required: Int 
      xs foldLeft("") { (a: String, x: Wrapper[String]) => a + x } 
                  ^

수정이 xs.foldLeft("") ...했다,하지만 컴파일러는 지능에 기대하는 이유 궁금되었다 이 경우. 이것이 파싱되는 방식을 조명 할 수 있습니까? 이것은 하루 종일 잔소리하고있다.

답변

2

점과 괄호를 생략하면 소위 중온 사료 표기법을 사용합니다. a.+(b) 대신 a + b을 쓸 수 있습니다. 여기서 중요한 규칙은 (SLS 6.12.3 참조) 호출 형태 object method paramlist의 경우이 만 허용한다는 것입니다 :

The right-hand operand of a left-associative operator may consist of several arguments enclosed in parentheses, e.g. e op (e 1 , ... , e n) . This expression is then interpreted as e.op(e 1 , ... , e n) .

foldLeft

이 양식에 맞지 않는, 그것은 object method paramlist1 paramlist2을 사용합니다.

A postfix operator can be an arbitrary identifier. The postfix operation e op is interpreted as e.op .

을하지만 다른 여기에 적용되는 규칙이있다 : 당신이 운영자 표기법이 쓰기 때문에 경우 (SLS 6.12.2에 설명 된대로) 컴파일러는 object.method(paramlist1).paramlist2으로 처리 기능 응용 프로그램 (SLS 6.6는).

An application f(e 1 , ... , e m) applies the function f to the argument expressions e 1 , ... , e m .

[...]

If f has some value type, the application is taken to be equivalent to f.apply(e 1 , ... , e m) , i.e. the application of an apply method defined by f .

여기에 우리가 간다 :

scala> { (a, x) => a + x } 
<console>:12: error: missing parameter type 
       { (a, x) => a + x } 
       ^
<console>:12: error: missing parameter type 
       { (a, x) => a + x } 
        ^

이는 형태 인수를 벗어났습니다 단지 함수 리터럴입니다. 우리가 그들을 추가하면 모든 것이 잘 컴파일 :

scala> { (a: String, x: Wrapper[String]) => a + x } 
res6: (String, Wrapper[String]) => String = <function2> 

이 컴파일러는 바로 위에서 설명한 기능을 응용 프로그램에 대한 규칙을 적용

scala> "" { (a: String, x: Wrapper[String]) => a + x } 
<console>:13: error: type mismatch; 
found : (String, Wrapper[String]) => String 
required: Int 
       "" { (a: String, x: Wrapper[String]) => a + x } 
               ^

scala> "" apply { (a: String, x: Wrapper[String]) => a + x } 
<console>:13: error: type mismatch; 
found : (String, Wrapper[String]) => String 
required: Int 
       "" apply { (a: String, x: Wrapper[String]) => a + x } 
                 ^

따라서, 귀하의 코드는

scala> xs foldLeft ("").apply{ (a: String, x: Wrapper[String]) => a + x } 
<console>:14: error: type mismatch; 
found : (String, Wrapper[String]) => String 
required: Int 
       xs foldLeft ("").apply{ (a: String, x: Wrapper[String]) => a + x } 
                    ^

왜으로 해석됩니다 함수 응용 프로그램 규칙이 적용됩니까? 접미사 연산자로 함수 리터럴을 적용 할 수도 있습니다.표시된 오류 메시지가 표시되는 이유는 SLS Scala Syntax Summary입니다. 거기에서 우리는 다음을 참조 할 수 있습니다 설명 섹션에서

InfixExpr   ::= PrefixExpr 
         | InfixExpr id [nl] InfixExpr 
    PrefixExpr  ::= [‘-’ | ‘+’ | ‘~’ | ‘!’] SimpleExpr 
    SimpleExpr  ::= ‘new’ (ClassTemplate | TemplateBody) 
         | BlockExpr 
         | SimpleExpr1 [‘_’] 
    SimpleExpr1  ::= Literal 
         | Path 
         | ‘_’ 
         | ‘(’ [Exprs] ‘)’ 
         | SimpleExpr ‘.’ id 
         | SimpleExpr TypeArgs 
         | SimpleExpr1 ArgumentExprs 
         | XmlExpr 
    Exprs    ::= Expr {‘,’ Expr} 
    ArgumentExprs  ::= ‘(’ [Exprs] ‘)’ 
         | ‘(’ [Exprs ‘,’] PostfixExpr ‘:’ ‘_’ ‘*’ ‘)’ 
         | [nl] BlockExpr 

을 우리는 InfixExpr는 중위 식을 설명하면서 ArgumentExprs 기능 응용 프로그램을 설명하는 알 수 위. EBNF의 규칙으로 인해 가장 상위의 규칙이 우선 순위가 가장 낮습니다. 그리고 이전 규칙은 후자에 의해 호출되기 때문에, 함수 리터럴이 중위 표현식 앞에 적용되므로 오류 메시지가 적용됩니다.

+0

자세한 답변을 보내 주셔서 감사합니다. 마지막 예제만으로도 완벽하게 이해할 수 있지만 SLS의 발췌 내용은 훨씬 더 많은 맥락을 추가합니다. – jroesch

1

이진 연산자은 중절 표기법으로 만 사용할 수 있다고 생각합니다. 나는 또한 괄호를 사용하여 상황을 개선 할 수 있다고 생각한다. (xs foldLeft ("")) {(a : String, x : Wrapper [String]) => a + x}. 아마 원래 코드를 xs.foldLeft("").{ (a: String, x: Wrapper[String]) => a + x }으로 구문 분석합니다. 이 대답을 확인하십시오 : When to use parenthesis in Scala infix notation