Skip to content

Instantly share code, notes, and snippets.

@nattybear
Last active August 20, 2021 02:40
Show Gist options
  • Save nattybear/16910b4aca976819a78c80ce2d4ba6ae to your computer and use it in GitHub Desktop.
Save nattybear/16910b4aca976819a78c80ce2d4ba6ae to your computer and use it in GitHub Desktop.
하스켈 polymorphism

이 글은 위키북스 하스켈을 읽고 정리한 것이다.

forall a

polymorphic 함수는 여러 타입에 적용할 수 있는 함수를 말한다.

함수 length는 아무 타입의 리스트에나 적용할 수 있다. [Char]를 넣어도 되고 [Int]를 넣어도 된다.

ghci> length "abc"
3
ghci> length [1,2,3,4]
4

length에 아무 타입의 리스트나 넣을 수 있다는 것을 타입 변수 type variable a로 나타낸다. 템플릿, 제네릭스 안습

length :: [a] -> Int

아래 함수들도 마찬가지이다.

fst :: (a, b) -> a
snd :: (a, b) -> b
map :: (a -> b) -> [a] -> [b]

Int, String 같은 구체적인 타입은 첫글자를 대문자로 적지만 타입 변수는 첫글자를 소문자로 적어야 한다. 이렇게 적으면 구체적인 타입과 타입 변수를 구별하기 좋다.

a에 아무 타입이나 올 수 있다는 것을 아래처럼 표현할 수도 있다.

length :: forall a. [a] -> Int

원래 방법대로 forall을 적지 않더라도 컴파일러가 알아서 forall을 넣어준다고 한다.(Haskell98에서는 그렇지 않다) 그래서 함수 fst의 타입은 사실 아래와 같다.

fst :: forall a. forall b. (a,b) -> a

아래처럼 적을 수도 있다.

fst :: forall a b. (a,b) -> a

같은 방식으로 함수 map의 타입은 아래와 같이 적을 수 있다.

map :: forall a b. (a -> b) -> [a] -> [b]

이렇게 아무 타입이나 넣을 수 있는 것을 universal quantification이라고 한다.

수학에서는 기호 를 사용하고 for all라고 발음한다. 턴에이가 아니다

Higher rank types

Haskell98에서는 아래와 같이 적으면 에러가 난다.

bar :: (a -> a) -> (Char, Bool)
bar f = (f 'c', f True)

왜냐하면 위 코드가 가능하려면 함수 f가 아래 타입을 동시에 만족해야 하는데

  • Char -> Char
  • Bool -> Bool

Haskell98에서는 a -> a 같은 다형성 함수가 동시에 한가지 타입만 적용할 수 있기 때문이다.

이 때 함수 barrank-1 타입이라고 한다.

반면에 아래 함수 foo와 같이 forall을 명시적으로 적어주면 동시에 여러 타입을 적용할 수 있게 된다!

foo :: (forall a. a -> a) -> (Char, Bool)
foo f = (f 'c', f True)

함수 foorank-2 타입이다.

이렇게 rank를 다루는 것이 System F라는 것과 관련이 있다고 한다.

Haksell98은 Hindley-Milner 타입 시스템을 사용한다. 제한된 System F 같은 것인데 forall rank-2 이상의 타입을 지원하지 않는다.

System F를 제대로 사용하려면 RankNTypes 확장을 사용해야 한다.

Haskell98

Haskell98에서 forall을 지원하지 않는 것이 아니라 forall을 지원하기는 하는데 아래 코드와 같이 맨 앞에만 적을 수 있다. outermost level

 bar :: forall a. ((a -> a) -> (Char, Bool))

forall 기능이 없어서 못 적는 것이 아니라 맨 앞에 밖에 못 써서 적으나마나 rank-1 타입 밖에 안 된다.

대문 링크

@kwanghoon
Copy link

[수정 제안]
Haksell98은 Hindley-Milner 타입 시스템을 사용한다. 제한된 System F 같은 것인데 forall나 rank-2 이상의 타입을 지원하지 않는다.
==>
Haksell98은 Hindley-Milner 타입 시스템을 사용하는데 전체 타입의 맨 앞에서만 forall을 사용할 수 있다. 따라서 프로그래머가 forall을 명시적으로 작성하지 않아도 되고, rank-2이상의 타입을 지원하지 않는다.

@nattybear
Copy link
Author

@kwanghoon 수정 제안에 감사드립니다! 사실 원문에는 아래 코드에 대한 언급이 있습니다.

 bar :: forall a. ((a -> a) -> (Char, Bool))

아마도 위 코드가 말씀하신 것에 대한 내용인 것 같군요.

@kwanghoon
Copy link

👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment