하스켈은 typeclass instance를 전역적으로 1개만 만들 수 있고

러스트는 애초에 impl 블럭 위치를 제한해서 여러개 impl이 생기지 않도록 문법적으로 제한을 한다고 알고 있는데


나는 그냥 여러개 만들 수 있게 허용해도 될것 같음.


class Foo a where

...

Foo a => ...

는 사실


data Foo a = ...

Foo a -> ...

랑 동등함.


여기서 더 나가서, 나는 인스턴스도 그냥 함수에 값 전달하듯이 쓰는게 가능해야 한다고 생각함. 그러니까 타입클래스 인스턴스도 first class citizen으로 다루는거지

물론 매번 명시적으로 적용하려면 힘드니까 문법적인 설탕을 많이 쳐서 전역/특정 스코프 내에서 적용되는 default instance 라던가, 함수 스코프 내에서 인스턴스 자동 적용 같은 방법을 써서 자동으로 적절한 인스턴스를 적용할 수 있게 해야겠지.

예를 들어서

f :: Ord a => a -> a -> a -> a

f x y z = g (g x y) z


g :: Ord a => a -> a -> a

g x y = if x > y then x else y


default Ord Int = ...


main = print $ f 1 2 3

라고 한다면 f에서 g를 호출할때에는 자동으로 f가 인자로 받은 Ord a를 사용하고, main에서 f를 호출할 때에는 전역 디폴트 인스턴스를 자동 적용하는거임.


그런데 하스켈에 인스턴스가 여러개 생기면 생기는 문제가 있는데

data Map k a = ...

empty :: Map k a

insert :: Ord k => k -> a -> Map k a -> Map k a

이건 하스켈 Map 데이터 구조 정의 일부분인데, Map이 이진 트리를 사용하는 자료구조라서 insert에서 Ord 인스턴스가 바뀌면 내부 정렬된 상태가 깨져서 문제가 발생함.


이건 Map 데이터 안에 Ord k 를 넣어서 해결할 수 있다.

그러니까

data Map k a = Map (Ord k) (Tree k a)

empty :: Ord k -> Map k a

insert :: k -> a -> Map k a -> Map k a

이런식으로 처음 Map을 생성할때 인자로 준 인스턴스를 데이터 구조안에 저장해두고 그걸 사용하게 하는거임.


이것 말고 인스턴스가 여러개일때 문제가 생기는 다른 경우가 있는지는 잘 모르겠다.

러스트는 경우에 따라 성능에 해가 될것 같기도 하고..


어쨋든 이런것도 허용해주면 나름대로 쓸모가 있을것 같음.

가령 Bool 같은건 Monoid 구조가 여러개 있어서 1개만 결정하기 어려움.

그래서 하스켈은 래퍼타입을 만들어서 각 래퍼 타입마다 인스턴스를 1개씩 구현함.

만약 복수개 인스턴스가 허용된다면 원하는 인스턴스를 인자로 전달해서 사용할 수 있겠지