2011-10-05 9 views
4

나는 실험적인 라이브러리를위한 DSL을 만들고있다. 나는 스칼라에서 빌드하고 있는데, 스칼라의 타입 추론에 대해 람다 식의 인자와 관련이 있기 때문에 괴롭다. 책 Programming In Scala에서 다루지 않는 것 같습니다.복잡한 스칼라 타입 추론 람다 식에서

내 라이브러리에는 T 유형의 개체에 적용 할 수있는 임시 한정자를 나타내는 데 사용되는 Effect [-T] 특성이 있습니다. 개체 myEffects에 + =는 Effect [PlayerCharacter] 유형의 인수를 받아들입니다. 마지막으로 [T] 일 때 일반적인 방법이 있는데 조건식을 수락하여 조건부 효과를 만들고 다른 효과를 인수로 사용합니다. 다음과 같이 서명은 : 나는 그것이 + = 방법을 초래할 것 통과, 위의 서명과 함께 "때"메소드를 호출

def when[T](condition : T => Boolean) (effect : Effect[T]) : Effect[T] 

, 람다 표현식 인수의 유형을 추론 할 수 없습니다.

myEffects += when(_.hpLow()) (applyModifierEffect) //<-- Compiler error 

나는 하나의 매개 변수 목록에 스칼라가 잘 람다 식의 유형을 추론 할 수있다 "때"의 인수를 결합합니다.

def when[T](condition : T => Boolean, effect : Effect[T]) : Effect[T] 

/* Snip */ 

myEffects += when(_.hpLow(), applyModifierEffect) //This works fine! 

두 번째 매개 변수를 완전히 제거해도 작동합니다.

def when[T](condition : T => Boolean) : Effect[T] 

/* Snip */ 

myEffects += when(_.hpLow()) //This works too! 

그러나, 심미적 인 이유로, 난 정말 인수가 별도의 매개 변수 목록으로 "때"메서드에 전달되어야합니다.

Programming in Scala의 16.10 절을 이해하면 컴파일러는 먼저 메서드 형식을 알고 있는지 여부를 확인하고 예상되는 형식의 형식을 유추하는 데 사용합니다. 이 경우 가장 바깥 쪽 메서드 호출은 + =이며 Effect [PlayerCharacter] 형식의 인수를 받아들입니다. [T]가 Effect [T] 일 때의 리턴 타입은 결과가 전달되는 메소드가 Effect [PlayerCharacter] 타입의 인수를 기대하기 때문에 T는 PlayerCharacter이고 따라서 람다의 타입 expression이 "when"이 PlayerCharacter => Boolean 인 첫 번째 인수로 전달되었습니다. 이것은 인수가 하나의 매개 변수 목록에 제공 될 때 작동하는 것처럼 보입니다. 그렇다면 인수를 두 개의 매개 변수 목록으로 나누면 왜 작동하지 않습니까?

+1

http://pchiusano.blogspot.com/2011/05/making-most-of-scalas-extremely-limited.html – retronym

답변

2

필자는 스칼라에 대한 새로운 지식을 가지고 있으며 형식 유추가 어떻게 작동하는지에 대한 상세한 기술적 지식을 많이 가지고 있지 않습니다. 그러니 소금 한 알씩 먹는게 가장 좋습니다.

차이점은 컴파일러가 두 개의 매개 변수 목록 버전에서 두 Tcondition : T => Booleaneffect : Effect[T]에서 동일하다는 것을 증명하는 데 문제가 있다고 생각합니다.

여러 매개 변수 목록이있는 경우 (스칼라에서는 다음 매개 변수 목록을 사용하는 함수를 반환하는 메서드를 정의하는 것으로 간주하므로) 컴파일러는 매개 변수 목록을 한 번에 하나씩 처리합니다 매개 변수 목록 버전. 그래서이 경우

:

def when[T](condition : T => Boolean, effect : Effect[T]) : Effect[T] 

/* Snip */ 

myEffects += when(_.hpLow(), applyModifierEffect) //This works fine! 

applyModifierEffect의 종류와 _.hpLow()의 매개 변수 유형을 제한 할 수 있습니다 myEffects += 필요한 매개 변수 유형; T은 모두 PlayerCharacter이어야합니다.그러나 다음에 :

myEffects += when(_.hpLow()) (applyModifierEffect) 

컴파일러는 applyModifierEffect에 적용하는 것이 유효인지는 확인할 수 있도록 독립적으로 when(_.hpLow())의 유형을 파악해야한다. 그리고 자체적으로 _.hpLow()은 컴파일러가 when[PlayerCharacter](_.hpLow())이라는 것을 추론 할 수있는 충분한 정보를 제공하지 않으므로 반환 유형이 Effect[PlayerCharacter] => Effect[PlayerCharacter] 유형의 함수라는 것을 알지 못하므로 적용하기에 적절하지 않습니다. 그 맥락에서 그 기능. 내 생각 엔 형식 유추는 점을 연결하지 않고 형식 오류를 피하는 정확히 한 가지 유형이 있다는 것을 알 수 있습니다. 여기

def when[T](condition : T => Boolean) : Effect[T] 

/* Snip */ 

myEffects += when(_.hpLow()) //This works too! 

when 및 매개 변수 형식의 반환 형식이보다 직접적으로 매개 변수 유형과 만든 추가 기능의 반환 형식을 거치지 않고, 연결되어 :

그리고 작동하는 다른 케이스로

카레로. myEffects +=에는 Effect[PlayerCharacter]이 필요하므로 T은 이어야하며 hpLow 방법이 있으며 컴파일러가 완료됩니다.

정보가 풍부한 사람이라면 세부 정보를 수정할 수 있기를 바랍니다. 그렇지 않으면 잘못된 트리를 모두 짖고 있습니다.

+0

정확할 수도 있습니다.필자는 여러 매개 변수 목록이있는 함수를 실제로 카레로 생각하지 않습니다. 호출 할 때 누락 된 인수 목록 대신 밑줄을 사용해야하기 때문입니다. 반면에 "def"와 같이 명시 적으로 카레 함수가있는 경우에는 curried (x : Int) = (y : Int) => x + y "이면 밑줄을 사용할 필요가 없습니다. 그러나 아마도 스칼라가 이러한 유형의 함수를 처리하는 방법에 대한 나의 정신 - 모델은 약간의 수정이 필요합니다. – Nimrand

+0

@ 님란 아, 그렇게하기 위해 밑줄을 추가해야한다는 것을 몰랐습니다. 여러 매개 변수 목록을 사용하면 컴파일러가 첫 번째 목록에 제공된 매개 변수를 기반으로 형식 매개 변수를 완전히 수정한다는 것을 알고 있습니다 (때로는 유용하므로 모호성을 피하기 위해 명시 적 힌트가 필요하지 않으며 때때로 수동으로 해결할 수있는 형식 오류가 발생합니다). 형식 주석). 여러 매개 변수 목록은 명시 적으로 함수를 사용하는 것과 동일한 대우를받지 못하는 경우에도 형식 유추 자에 의해 다르게 처리됩니다. – Ben

2

내 생각에, 당신이 말하는 작품이 없어야하고 실제로 그 중 하나를 만들 수 없기 때문에 약간 혼란 스럽습니다.

유형 추론은 매개 변수 목록이 아닌 매개 변수 목록에서 왼쪽에서 오른쪽으로 작동합니다. 전형적인 예는 컬렉션 방법 foldLeft이다

def foldLeft[B] (z: B)(op: (B, A) => B): B 

Z 의지의 유형 B 공지하게되므로 OP가 기록 될 수 B를 지정하지 않고 (도 아니고 개시로부터 공지 된 입력 파라미터 (서열은 [A]라고) 이의). 루틴이

def foldLeft[B](z: B, op: (B,A) => B): B 

로 서면 또는 경우

def foldLeft[B](op: (B,A) => B)(z: B): B 

로는 작동하지 않을 것, 하나는 확실 연산 유형이 명확하게, 또는 foldLeft를 호출 할 때 B 명시 적으로 전달해야합니다. 귀하의 경우에는

, 나는 동등한 읽을 가장 쾌적한 당신이 다음

Effects += applyModifierEffect when (_.hpLow()) 

로를 작성합니다 whenEffect의 방법을 (또는 암시 적 변환과 하나처럼 보이게)하는 것입니다 생각 당신은 효과가 반쪽 변이라고 표현한 경우, 이기 때문에 when 시그니처는 Effect의 메서드에 허용되지 않습니다. 함수는 첫 번째 형식 매개 변수에서 반올림되며 조건은 매개 변수로 나타나므로 반역 위치에서 두 개의 반쪽 문자는 공변수), 암시 적으로

을 사용하여 수행 할 수 있습니다
object Effect { 
    implicit def withWhen[T](e: Effect[T]) 
    = new {def when(condition: T => Boolean) = ...} 
} 
+0

'foldLeft'가'def foldLeft [B] (z : B, op : (B, A) => B) : B'로 쓰여진다면,'z'에 대한 값을 전달하면 bind 할 것이기 때문에 여전히 동작하지 않을까요? B 형? 아니면 매개 변수 목록에있는 모든 유형이 같은 목록의 다른 것들과 독립적으로 추론 할 수 있어야합니까? – Ben

+0

두 번째. 이전 매개 변수 목록에서 얻은 정보 만 사용할 수 있습니다. –

+0

인수에서 유추 된 형식 매개 변수가 첫 번째 인수 목록 만 사용되는 경우 올바른 것입니다. 그 이유는 그것이 "when"의 type 매개 변수를 추론 할 수있는 이유는 결과가 Effect [PlayerCharacter] 유형의 인수를 예상하는 메서드에 전달되고 있으므로 "when"의 예상 유형이 Effect입니다 [ PlayerCharacter]이므로 T의 유형은 PlayerCharacter (또는 더 넓은 유형) 여야합니다. 나는 단지 "언제"라고 부르면, 나는 어떤 예제도주지 않았다. – Nimrand

관련 문제