왜 커링을 해야 형식추론을 더 잘하는지 궁금합니다.

115 views
Skip to first unread message

cybaek

unread,
May 19, 2015, 10:30:24 PM5/19/15
to scala...@googlegroups.com
안녕하세요 ^^
<FP in Scala>를 읽으면서 궁금한 점이 생겨 질문 올립니다..

3.3.2에서 "고차 함수를 이용한 형식 추론 개선"에 대해 설명합니다.

다음과 같은 함수의 경우, 반드시 f 인자의 타입을 명시하라고 합니다.

정의:
def dropWhile[A](l: List[A], f: A => Boolean): List[A]

사용:
val xs = List[Int] = List(1, 2, 3, 4)
dropWhile(xs, (x: Int) => x < 4))

커링을 찾아 읽어도 봤지만, 왜 호출할 때 (x: Int)와 같이 Int를 명시해야하고,
커링을 하면 명시할 필요가 없는지 잘 이해가 안갑니다.

A로 타입을 명시했고 xs의 List가 Int임을 아는데 왜 명시해야하나요?

- 낭만검객


Joseph Yang

unread,
May 20, 2015, 2:15:36 AM5/20/15
to scala...@googlegroups.com
안녕하세요.

저도 책읽다 궁금해서 찾아봤었는데, 

스칼라 컴파일러의 타입 추론 쪽에 문제가 있어서
타입의 전달이 인자 그룹 내에서 적용 되지 않는다고 해요.
예를 들어 xs 의 Int라는 타입이 함수 f의 타입 추론에 영향을 주지 못해서 알 수없는 타입이라고 나오는 것이구요.

그런데 커링으로는 타입이 왼쪽에서 오른쪽으로 전달이 된다고 하는군요.
그래서 dropwhile(xs)(x => x < 4) 이렇게 쓰는거구요.

이유는 스칼라 컴파일러쪽에 있다고하는데.... 잘아시는분이 설명해주실꺼 같아요. :)




2015년 5월 20일 오전 11:30, cybaek <cyb...@gmail.com>님이 작성:

--
이 메일은 Google 그룹스 '라 스칼라 코딩단' 그룹에 가입한 분들에게 전송되는 메시지입니다.
이 그룹에서 탈퇴하고 더 이상 이메일을 받지 않으려면 scala-korea...@googlegroups.com에 이메일을 보내세요.
이 그룹에 게시하려면 scala...@googlegroups.com에 이메일을 보내세요.
웹에서 이 토론을 보려면 https://groups.google.com/d/msgid/scala-korea/77c86bc7-4cb9-4304-b866-8c42351859eb%40googlegroups.com을(를) 방문하세요.
더 많은 옵션을 보려면 https://groups.google.com/d/optout을(를) 방문하세요.



--
/*******************************************/
/* Get busy living, Get busy dying      */
/*******************************************/

Young-Rok Bahn

unread,
May 20, 2015, 4:00:02 AM5/20/15
to scala...@googlegroups.com
scala는 local type inference 알고리즘을 사용해서 local scope안에 있는 타입만 유추가 가능합니다. 그래서 인수가 함수이거나 객체의 맴버변수에 대한 타입 추론은 할수가 없습니다. 그에 반해 haskell 는 complete type inference 알고리즘을 사용해서 굳이 그런 꽁수를 쓸 필요가 없다고 하네요. 



2015년 5월 20일 오후 3:15, Joseph Yang <befo...@gmail.com>님이 작성:

Hyunsok Oh

unread,
May 20, 2015, 5:37:44 AM5/20/15
to scala...@googlegroups.com
ML이나 하스켈의 타입 체커는 전역 타입 체킹을 하면서, 여러 타입을 가능하면 하나로 통합하는 unification이라는걸
해서 타입을 해결합니다(사실 이게 인간의 타입 추론 로직과 가장 비슷하겠죠)

예를 들어:

def dropWhile[A](l: List[A], f: A => Boolean): List[A] = l.dropWhile(f)
def dropWhile2[C](l: List[C])(f: C => Boolean): List[C] = l.dropWhile(f)
val xs: List[Int] = List(1, 2, 3, 4)
dropWhile(xs, _ < 4) // 컴파일 오류 (가)
dropWhile2(xs)(_ < 4) // 잘 됨

(가) 위치에서 ML이나 하스켈에서는 다음 세가지 사실을 가지고 타입을 unification합니다.

1) dropWhile의 타입: (List[A], A => Boolean) => List[A]
2) xs의 타입: List[Int]
3) _ < 4의 타입: (정수와 <로 비교할 수 있는 타입 B) => Boolean

4) 1)과 2)로부터 => dropWhile의 타입 매개변수 A는 Int
5) 4)와 1)로 부터 => dropWhile의 함수 인자는 Int => Boolean
6) 5)와 3)으로부터 => _ < 4의 타입은 Int => Boolean

그런데 스칼라는 흐름기반의 로컬 타입추론이라서, 이런짓을 안하고 모르는건 모른다고 한답니다 --;;
그럼 왜 커링을 하면 되느냐?

dropWhile2(xs)(_ < 4) 은 먼저 dropWhile2(xs)를 적용하면서 타입을 검사합니다. 따라서 xs의
타입으로부터 C가 Int라는걸 알수 있죠. 그래서 이 부분적용함수의 타입은 (Int => Boolean) => List[A]가
됩니다. 그러니 당연히 그 다음에 (_ < 4)를 적용하면 _가 Int라는걸 추론할 수 있죠.

그럼 왜 흐름기반으로 만들었느냐? 프로그래밍 스칼라에 따르면 흐름기반 지역 타입추론이 더 객체지향과 잘 어울린다는데(정확히
말하면 unification기반 전역 타입추론을 하면, 약간의 언어 변경만으로도 타입 체커가 참 거짓을 판단하는 능력(이를
결정가능성 decidiblilty 이라고 하죠)이 확확 바뀐다고 합니다) 이론적으로 왜 그런지는 따로 찾아봐야 할것 같습니다.
(아마 스칼라 메일링 리스트 등에 질문을 해보셔야 할 것 같네요.) 오더스키의 논문이 있긴
한데(http://lampwww.epfl.ch/~odersky/papers/popl01.pdf)학계를 떠난지 오래되서 읽기가
귀찮네요.

참고로 이와 관련된 타입 추론 관련 이야기는 "프로그래밍 인 스칼라" 한글책 384페이지에 나옵니다. ^^;;

cybaek

unread,
May 20, 2015, 10:09:27 AM5/20/15
to scala...@googlegroups.com
고맙습니다!! ^^
Reply all
Reply to author
Forward
0 new messages