타입 클래스, 타입 추론, Dependent Haskell

Posted on June 17, 2020

타입 클래스

정적 타입이란, 컴파일 타임에 지정된 타입끼리 만나지 않는 상황이 생기면 마리 알려줘서 실행 타임에 오류를 줄이자는 것입니다. 그런데, 이 장점을 이용하려다 보니, 코딩시 일일이 타입을 “고정” 해야 하는 단점이 있습니다. 타입이 고정되면, 비슷한 동작을 하는, 아니 거의 같은 동작을 하는 함수들을 타입에 따라 모두 준비해야 합니다. (+) 함수를 정의하는데, Int 값을 받아들이게 만들었다면, Float 를 위한 (+) 를 또 만들어야 합니다.

정적 타입 언어인 하스켈에서 타입 클래스 + 타입 추론을 써서 위와 같은 개념을 구현합니다.

코딩할 때, 타입을 고정하지 않고 열어 두면, 컴파일러가 타입 추론을 이용해 타입을 고정합니다. 열어 둘 때 활짝 열어 아무 타입이나 다 가능하게 해 놓을수도 있고, 살짝 열어, 특정 성격의 타입만 받아들이게 할 수 있습니다.

타입 추론

폴리모픽 매개 변수 forall a. a를 두면, GHC가 코드 조합을 할 때, 타입 결정을 뒤로 미루는 효과가 납니다. 하스켈의 타입 추론은 마치 하스켈의 Lazy한 함수 실행처럼 Lazy하게 타입을 결정합니다. 어떤 분류의 타입만 받게끔 해서 코드를 조합하다가 구체 타입이 필요한 시점이 되서야 타입이 뭔지 결정합니다. 심지어 끝끝내 구체 타입을 알 필요가 없는 경우도 있긴 있습니다.(ex. length함수, 컨테이너 안에 들어 있는 엘리먼트 수만 세기때문에 엘리먼트 뭔지 알필요가 없습니다.)
어찌됐든 GHC가 알아서 단서들을 모아서 타입 추론을 하는데, 이 때 GHC가 써먹도록 만드는게 타입 레벨 함수입니다.

타입 레벨 프로그래밍

Dependent Haskell

이렇게 할 수 있는 이유는, 하스켈은 강력한 타입 추론 기능을 가지고 있기 때문입니다. 이렇게 강력한 기능을 좀 더 적극적으로 써보자는 개념이 Dependent Haskell 입니다. (하스켈에서 가지를 친 이드리스Idris 언어는 이 개념에 특화되어 있는 언어입니다.)

Dependent Function
https://serokell.io/blog/why-dependent-haskell

카인드 Kind

Int를 받고 Int를 내뱉는 함수라면, 2같은 값을 받아 연산해서 3같은 값을 결과로 내 뱉습니다.
* -> * 카인드를 받고 * 카인드를 내 뱉는 타입 레벨 함수는 결과로 Int같은 타입을 내 뱉습니다.

1,2,3… 등을 뭉뚱그려서(추상화 해서) Int 타입이라 분류했습니다.
Int, Double, Char 등을 뭉뚱그려서 * 카인드로 분류하고
Maybe a, List a, Some a 등을 뭉뚱그려서 * -> * 카인드로 분류합니다.

값은 타입으로 분류하고(추상화하고), 타입은 카인드로 분류(추상화)합니다.

런타임에는 타입이 없다

타입은 컴파일 타임에 코드를 “조립”할 때만 필요합니다. 예를 들어, 반드시 Int 타입만 받게 지정해 놓은 타입에 Double을 내뱉는 코드 조각이 맞춰지는 상황이 오면 문제를 잡아냅니다. 이렇게 타입 체크를 일일이 하면서 문제 없이 모든 코드 조각을 맞췄다면(타입 추론을 통과했다면), 타입이 달라 문제가 생기는 경우는 없게됩니다. 그러면 런타임에는 굳이 타입 정보를 끌고 다녀야 할 이유가 없어집니다. 그렇기 때문에 타입 레벨 프로그래밍도 컴파일 타임까지만 노리고 개념을 활용하는데, 너무 적극적으로 쓰다 보면 런타임에도 타입 레벨에 있는 정보가 필요할 때가 있습니다. 이럴 때 싱글턴 라이브러리의 도움을 받습니다.

참고 - stackoverflow - type level programming meaning at run time

싱글턴 라이브러리

런타임에는 타입 정보가 모두 사라집니다. 컴파일 타임을 넘어 런타임에도 타입 레벨에 있는 정보가 필요할 경우, 값 레벨로 정보를 복사해 놓을 때 쓰는 라이브러리입니다.
https://ryanglscott.github.io/2019/08/29/how-ghc-8-8-nearly-killed-singletons/
https://blog.jle.im/entry/introduction-to-singletons-1.html

필요한 확장

TypeFamilies
DataKinds
PolyKinds
GADTs
RankNTypes
ScopedTypeVariables
TypeApplications
TypeOperators
MultiParamTypeClasses
FlexibleContexts
FlexibleInstances

… 계속

미완성 포스트

Github 계정이 없는 분은 메일로 보내주세요. lionhairdino at gmail.com