Rust의 특성과 Haskell의 유형 클래스의 차이점은 무엇입니까?


157

Rust의 특성 은 Haskell의 형식 클래스 와 적어도 피상적으로 비슷해 보이지만 사람들은 그들 사이에 약간의 차이가 있다고 봅니다. 이러한 차이점이 무엇인지 정확히 궁금했습니다.


8
나는 녹에 대해 많이 모른다. 그러나 다른 언어에서 유사한 기술에 대한 일반적인 걸림돌은 종류가 더 높으며 (예 : 특성이 매개 변수화 된 유형에 비해 범위가 다양 할 수 있지만 매개 변수가 아닌가?) 반환 유형 다형성 (예 : 특성 유형은 함수의 결과에 나타날 수 있지만 어디에도 해당되지는 않음) 논쟁에서?). 하스켈에서의 전자의 예는 class Functor f where fmap :: (a -> b) -> (f a -> f b); 후자의 예는 class Bounded a where maxBound :: a입니다.
Daniel Wagner

4
GHC는 또한 다중 매개 변수 유형 클래스 (즉, 여러 유형을 포함하는 특성) 및 기능 종속성을 지원하지만 공식 Haskell 스펙의 일부는 아닙니다. 귀하의 링크에서 제안 된 Rust 구문을 판단하면 한 번에 한 유형 이상의 특성 만 지원할 수 있지만 판단은 깊은 경험을 바탕으로하지 않습니다.
Daniel Wagner

4
@DanielWagner 리턴 형 다형성 (예 :)이 std::default있고 다중 매개 변수 특성 정렬 작업 (기능 종속성의 유사체 포함)이지만 AFAIK는 특권을받는 첫 번째 매개 변수를 해결해야합니다. 그러나 HKT는 없습니다. 그들은 장래의 희망 목록에 있지만 아직 수평선에 있지 않습니다.

4
또 다른 차이점은 고아 인스턴스의 처리입니다. Rust는 특성에 대한 새로운 impl을 작성할 수있는 위치에 대해 더 엄격한 일관성 규칙을 적용하려고합니다. 자세한 내용은 이 토론 을 참조하십시오 (특히 여기 )
Paolo Falabella

1
Rust는 Haskell의 유형 군만큼 강력하지는 않지만 관련 유형 및 동등 구속 조건을 지원합니다 . 또한 특성 객체 를 통해 실존 유형이 있습니다 .
Lambda Fairy

답변:


61

기본 수준에는 큰 차이가 없지만 여전히 있습니다.

Haskell은 타입 클래스에 정의 된 함수 나 값을 '메소드'로 설명합니다. 특성이 객체에있는 OOP 메소드를 설명하는 것과 같습니다. 그러나 Haskell은 이러한 방식을 다르게 처리하여 OOP로 인해 객체에 고정하는 대신 개별 값으로 취급합니다. 이것은 가장 명백한 표면 수준의 차이입니다.

Rust가 한동안 할 수 없었던 한 가지는 악명 높은 타입 클래스 와 같은 고차 타입의 특성 이었습니다 .FunctorMonad

이는 녹 특성이 흔히 '콘크리트 유형', 즉 일반적인 논증이없는 것을 설명 할 수 있음을 의미합니다. Haskell은 처음부터 고차 함수가 다른 함수를 사용하는 것과 비슷한 유형을 사용하는 고차 타입 클래스를 만들 수 있습니다. 한동안 이것은 Rust에서 불가능했지만 관련 항목 이 구현되었으므로 그러한 특성은 평범하고 관용적이되었습니다.

따라서 확장을 무시하면 정확히 같지는 않지만 각각 확장 할 수 있습니다.

주석에서 언급했듯이 GHC (Haskell의 주요 컴파일러)는 다중 매개 변수 (예 : 많은 유형의 유형) 유형 클래스 및 유형 수준 계산을 허용하는 멋진 옵션 인 기능 종속성을 포함하여 유형 클래스에 대한 추가 옵션을 지원 한다고 언급 할 수 있습니다 그리고 유형 패밀리로 이어집니다 . 내 지식으로는 Rust는 funDeps 나 type family를 가지고 있지 않지만 장래에있을 수도 있습니다. †

대체로 특성과 유형 분류에는 근본적인 차이가 있습니다. 특성과 상호 작용하는 방식으로 인해 결국 행동과 유사하게 보입니다.


† Haskell의 타입 클래스 (고 타입 타입 포함)에 대한 좋은 기사는 여기 에서 볼 수 있고 , 특성에 관한 예제에 의한 Rust 장은 여기 에서 찾을 수 있습니다.


1
녹은 여전히 ​​더 높은 종류의 종류가 없습니다. "유명"은 정당화가 필요하다. Functor는 믿을 수 없을 정도로 광범위하며 개념으로 유용합니다. 유형 패밀리는 연관된 유형과 동일합니다. 기능 의존성은 본질적으로 연관된 유형과 중복됩니다 (하스켈 포함). 녹에 wrt가 부족한 것. fundeps는 주입 주석입니다. 당신은 그것을 거꾸로 가지고 있으며, Rust의 특성과 Haskell의 유형 클래스는 표면에서 다르지만 아래를 볼 때 많은 차이가 증발합니다. 남아있는 차이점은 대부분 언어가 작동하는 다른 영역에 내재되어 있습니다.
Centril

많은 상황에서 관련 항목이 이제는 관념으로 간주됩니다.
Vaelus

@Vaelus 당신이 맞아요 —이 답변은 약간 업데이트되어야합니다. 지금 수정 중입니다.
AJFarmar

19

현재 답변이 Rust 특성과 Haskell 유형 클래스의 가장 근본적인 차이점을 간과한다고 생각합니다. 이러한 차이점은 특성이 객체 지향 언어 구성과 관련되는 방식과 관련이 있습니다. 이에 대한 정보는 Rust book을 참조하십시오 .

  1. 특성 선언은 특성 유형을 만듭니다 . 즉, 이러한 유형의 변수 (또는 유형의 참조)를 선언 할 수 있습니다. 특성, 구조체 필드 및 형식 매개 변수 인스턴스화에서 특성 유형을 매개 변수로 사용할 수도 있습니다.

    특성 참조 변수는 런타임에 참조 된 오브젝트의 런타임 유형이 특성을 구현하는 한 다른 유형의 오브젝트를 포함 할 수 있습니다.

    // The shape variable might contain a Square or a Circle, 
    // we don't know until runtime
    let shape: &Shape = get_unknown_shape();
    
    // Might contain different kinds of shapes at the same time
    let shapes: Vec<&Shape> = get_shapes();

    이것은 타입 클래스가 작동하는 방식이 아닙니다. 유형 클래스는 유형을 생성하지 않으므로 클래스 이름으로 변수를 선언 할 수 없습니다. 형식 클래스 는 형식 매개 변수에 대한 경계 역할을 하지만 형식 매개 변수는 형식 클래스 자체가 아닌 구체적 형식으로 인스턴스화해야합니다.

    동일한 유형 클래스를 구현하는 다른 유형의 여러 가지 목록을 가질 수 없습니다. (대신 Haskell에서는 실존 유형이 비슷한 것을 표현하기 위해 사용됩니다.) 주 1

  2. 특성 메소드는 동적으로 전달 될 수 있습니다 . 이것은 위 섹션에서 설명한 것과 밀접한 관련이 있습니다.

    동적 디스패치는 참조를 통해 호출되는 메소드를 판별하기 위해 참조가 가리키는 오브젝트의 런타임 유형이 사용됨을 의미합니다.

    let shape: &Shape = get_unknown_shape();
    
    // This calls a method, which might be Square.area or
    // Circle.area depending on the runtime type of shape
    print!("Area: {}", shape.area());

    또한 Haskell에서 실존 유형이 사용됩니다.

결론적으로

많은 측면에서 특성이 유형 클래스와 동일한 개념 인 것 같습니다. 또한 객체 지향 인터페이스의 기능이 있습니다.

반면에 하스켈의 타입 클래스는 더욱 발전했습니다. Haskell은 예를 들어 다중 매개 변수 유형 클래스와 같은 더 높은 종류의 유형과 확장을 가지고 있습니다.


참고 1 : 최신 버전의 Rust에는 특성 이름을 유형으로 사용하고 특성 이름을 경계로 사용하는 것을 구별하기 위해 업데이트되었습니다. 특성 유형에서 이름 앞에 dyn키워드 가 붙습니다 . 자세한 내용은 예를 들어이 답변 을 참조하십시오.


2
"유형 클래스는 유형을 만들지 않습니다"- dyn Trait특성 / 유형 클래스와 관련되어 있기 때문에 실재 타이핑 형식 으로 이해하는 것이 가장 좋습니다 . dyn유형에 투영하는 경계에 대한 연산자를 고려할 수 있습니다 dyn : List Bound -> Type. 이 아이디어를 Haskell에 가져 가서 "클래스 이름으로 변수를 선언 할 수 없습니다"와 관련하여 Haskell에서 간접적으로 수행 할 수 있습니다 data Dyn (c :: * -> Constraint) = forall (t :: Type). c t => D t. 이를 정의한 후 작업 할 수 있습니다 [D True, D "abc", D 42] :: [D Show].
Centril April

8

Rust의“특성”은 Haskell의 유형 클래스와 유사합니다.

Haskell과의 주요 차이점은 특성이 점 표기법 (예 : a.foo (b) 형식)이있는 표현식에만 개입한다는 것입니다.

하스켈 타입 클래스는 고차 타입으로 확장됩니다. 녹 특성은 전체 언어에서 누락되기 때문에 고차 유형 만 지원하지 않습니다. 즉 특성과 유형 클래스 사이의 철학적 차이가 아닙니다.


1
Rust의 특성은 "점 표기법이있는 표현식에만 개입"하지 않습니다. 예를 들어, Default메소드가없고 메소드와 연관된 함수 만없는 특성을 고려하십시오 .
Centril April
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.