하스켈은 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개씩 구현함.
만약 복수개 인스턴스가 허용된다면 원하는 인스턴스를 인자로 전달해서 사용할 수 있겠지
Rust impl 블록 개수랑 위치는 제한없는데
trait 정의, data 정의, impl 셋다 다른 파일에 못쓰는걸로 아는데
가능함
다른 라이브러리면?
나 님한테 들은 건데 ㅋㅋ
다른 라이브러리면 trait나 struct중 하나는 이쪽 타입이여야함
ㅇㅇ 그니까 같은 struct, trait에 대한 impl을 여러개는 못만들잖아
흠 무슨말 하는진 알겠는데 그런건 함수 매개변수에 넣거나 const generic으로 상수를 타입선언에 집어넣는다거나 하면 되지않음?
굳이 컨텍스트마다 구현체가 달라져야할 이유는 없을듯
음.. const generic이 상수를 전달해서 구현들을 구별한다는 뜻인가?
뭐 이런건 다른 해결 방법이 없는건 아니긴 하지. 그냥 데이터 타입 정의해서 해도 되고.. 근데 인스턴스 여러개를 동시에 쓸 필요가 있는 상황에서는 저런걸 지원하는게 좀 더 깔끔하게 나올것 같음. 애초에 오버헤드도 딱히 없을것 같음.