programing

Haskell에 "명백한"유형 클래스가 누락 된 이유

copysource 2021. 1. 16. 20:41
반응형

Haskell에 "명백한"유형 클래스가 누락 된 이유


객체 지향 언어를 고려하십시오.

객체 지향 프로그래밍 배경에서 온 대부분의 사람들은 Java CollectionList인터페이스 의 본질을 포착하는 다양한 언어의 공통적이고 직관적 인 인터페이스에 익숙합니다 . Collection자연적인 순서 / 인덱싱이 반드시 필요하지는 않은 객체 모음을 나타냅니다. A List는 자연스러운 순서 / 색인이있는 컬렉션입니다. 이러한 인터페이스는 다른 언어의 동등한 인터페이스와 마찬가지로 Java에서 많은 라이브러리 데이터 구조를 추상화하며 대부분의 라이브러리 데이터 구조에서 효과적으로 작동하려면 이러한 인터페이스에 대한 자세한 이해가 필요합니다.

Haskell로 전환 :

Haskell에는 객체의 인터페이스와 유사하게 유형에 대해 작동하는 유형 클래스 시스템이 있습니다. Haskell은 유형이 기능 을 고려할 때 Functor, Applicative, Monads 등과 관련하여 잘 설계된 유형 클래스 계층 구조 를 가지고있는 것 같습니다 . 그들은 분명히 정확하고 잘 요약 된 유형 클래스를 원합니다 . 당신이 많은 하스켈의 컨테이너에서 볼 때 아직 ( List, Map, Sequence, Set, Vector) 그들은 거의 모든 매우 유사한 (또는 동일) 기능을 가지고, 아직 형 클래스를 통해 추출되지 않습니다.

몇 가지 예 :

  • null "비어 있음"테스트 용
  • length/size 요소 수
  • elem/member 세트 포함
  • empty 및 / 또는 singleton 기본 구성
  • union 세트 유니온
  • (\\)/diff 세트 차이
  • (!)/(!!) 안전하지 않은 인덱싱 (부분 함수)
  • (!?)/lookup 안전한 인덱싱 (전체 기능)

위의 함수 중 하나를 사용하고 싶지만 두 개 이상의 컨테이너를 가져온 경우 가져온 모듈에서 함수를 숨기거나 모듈에서 필요한 함수 만 명시 적으로 가져 오거나 가져온 모듈을 한정해야합니다. 그러나 모든 기능이 동일한 논리적 기능을 제공하기 때문에 번거로운 것처럼 보입니다. 함수가 각 모듈에서 별도로 정의되지 않고 유형 클래스에서 정의 된 경우 컴파일러의 유형 추론 메커니즘이이 문제를 해결할 수 있습니다. 또한 유형 클래스를 공유하는 한 기본 컨테이너를 간단하게 전환 할 수 있습니다 (예 : 더 나은 임의 액세스 효율성 SequenceList위해 대신 a 사용하도록 합니다 ).

Haskell 에 이러한 함수 중 일부를 통합하고 일반화하기 위한 Collection및 / 또는 Indexable유형 클래스 가없는 이유는 무엇 입니까?


부분적으로 그 이유는 모나드와 화살이 Haskell의 새롭고 혁신적인 기능인 반면 컬렉션은 비교적 평범하기 때문입니다. Haskell은 연구 언어로서 오랜 역사를 가지고 있습니다. 흥미로운 연구 질문 (모나드 인스턴스 설계 및 모나드에 대한 일반 작업 정의)은 "산업용"폴리싱 (컨테이너 API 정의)보다 더 많은 개발 노력을 기울입니다.

부분적으로 그 이유는 이러한 유형이 세 가지 별도의 히스토리와 디자이너가있는 세 가지 다른 패키지 (기본, 컨테이너 및 벡터)에서 제공되기 때문입니다. 따라서 디자이너가 단일 유형 클래스의 인스턴스를 제공하기 위해 조정하기가 더 어려워집니다.

부분적으로, 그 이유는 언급 한 5 개의 컨테이너를 모두 포함하는 단일 유형 클래스를 정의하는 것이 정말 어렵 기 때문입니다. List, Sequence, Vector는 비교적 비슷하지만 Map과 Set은 완전히 다른 제약을가집니다. List, Sequence 및 Vector의 경우 간단한 생성자 클래스가 필요하지만 Set의 경우 요소 유형에 Ord 인스턴스가 필요하기 때문에 작동하지 않습니다. 설상가상으로 Map은 대부분의 메소드를 지원할 수 있지만 싱글 톤 함수에는 나머지 매개 변수가 하나만 필요한 두 개의 매개 변수가 필요합니다.


다른 답변에서 지적했듯이 Haskell은 다른 어휘를 사용하는 경향이 있습니다. 그러나 나는 그들이 그 차이 이유 를 잘 설명하지 못했다고 생각 합니다.

Java와 같은 언어에서 함수는 "일급 시민"이 아닙니다. 익명 함수가 최신 버전에서 사용 가능하다는 것은 사실이지만이 스타일의 인터페이스 (Collection, Indexable, Interable 등)는 그 전에 디자인되었습니다.

이로 인해 코드를 전달하는 것이 지루하므로 다른 사람의 데이터코드 로 전달 하는 것을 선호 합니다 . 예를 들면 :

  • 데이터 구현하는 자바는 Iterable할 수 있습니다 우리에게 쓰기for (Foo x : anIterable) { ... }
  • 데이터 구현하는 PHP의는 ArrayAccess할 수 있습니다 우리에게 쓰기anArrayAccess[anIndex]

즉 또 다른 방법이기 때문에이 스타일은, 발전기를 구현하는 객체 지향 언어로 볼 수 있습니다 우리가 작성하는 for yieldedElement in aGenerator: ....

Haskell은 유형 클래스에 대해 다른 접근 방식을 취합니다. 우리는 코드다른 사람의 데이터에 전달되는 것을 선호 합니다 . 몇 가지 (간단한) 예 :

  • Functors 우리의 코드를 받아들이고 '포함'하는 모든 요소에 적용합니다.
  • Monad우리의 코드를 받아들이고 일종의 '시퀀스'에 적용합니다.
  • Foldables 우리의 코드를 받아들이고 그것을 사용하여 내용을 '줄이기'

자바는 필요 Iterable하기 때문에 우리는 우리의 코드를 호출해야 할 우리의 for 우리가 반드시 올바르게라고 할 수 있도록, 루프. Haskell은 다른 사람의 코드 가 우리 코드 를 호출 할 것이기 때문에 더 구체적인 유형 클래스 가 필요하므로 어떻게 호출해야하는지 지정 해야합니다. 그것을이다 mapa는, foldAN, unfold등?

고맙게도 유형 시스템은 올바른 방법을 선택하는 데 도움이됩니다.)


lens패키지는이 중 일부를 제공합니다.

  • , 공허함에 대한 테스트 빈 용기 만드는 이들은 모두에 의해 제공됩니다 AsEmpty에서 typeclass을 Control.Lens.Empty.

  • key / index로 요소에 액세스 . At및 유형 Ixed클래스 Control.Lens.At.

  • 집합과 유사한 컨테이너의 멤버십 확인 . 의 유형 Contains클래스입니다 Control.Lens.At.

  • 시퀀스와 유사한 컨테이너에 요소 추가 및 삭제 . Cons및 유형 Snoc클래스 Control.Lens.Cons.

또한 typeclass pure메서드는 Applicative"단일"컨테이너를 만드는 데 자주 사용될 수 있습니다. Haskell의 functor / applicatives가 아닌 것들에 대해서는 Set아마도 pointfrom Data.Pointed을 사용할 수 있습니다.


Haskell에는 기본 패키지의 컬렉션 작업을위한 몇 가지 유형 클래스가 있습니다. Functor , FoldableTraversable 은 컬렉션 작업에 유용 할 수 있으며 Monoid , Applicative 및 / 또는 Alternative 유형 클래스는 컬렉션 구성에 유용 할 수 있습니다.

이 클래스는 함께 질문에서 언급 된 대부분의 작업을 다루지 만, 컨테이너 별 함수보다 효율성이 떨어질 수 있습니다 (이 중 대부분은 클래스 메서드이며 필요한 경우 기본 정의를 재정의 할 수 있음).

null "비어 있음"테스트 용

기본 4.8 null부터 접이식 지원 ( 이전 버전의 대안 임).any (const True)

요소 수의 길이 / 크기 :

기본 4.8 length부터 접이식 지원 ( 이전 버전의 대안 임).getSum . foldMap (const 1)

세트 포함을위한 elem / member

접이식 지원 elem, notElemmember.

기본 구성의 경우 비어 있거나 싱글 톤

비어있는 경우 memptyMonoid 및 emptyAlternative에서 제공됩니다. 싱글 톤의 경우 pureApplicative에서 제공합니다.

조합 조합

There is mappend from Monoid and <|> from Alternative. They don't necessarily implement set union, but they implement some form of union that works well together with empty and usually also with singleton and find.

(\)/diff for set difference

This one is not supported, unfortunately.

(!)/(!!) for unsafe indexing (partial function)

You could use fromJust together with a function for safe indexing.

(!?)/lookup for safe indexing (total function)

There is find from Foldable.


Such typeclasses exist in standard Haskell, but they don't have the same name as their equivalent OO counterparts. The Collection typeclass, for example, is called Foldable in Haskell. You can use it to test if a structure is empty (foldr (const False) True x) or to count the number of elements (foldMap (const 1) x), or to test for set membership (foldr (\e' present -> (e==e') || present) False x for some e).

For operations like element lookup, you have the Array typeclass which might work for sequential data. For more flexibility, you can write your own Indexable class, like this for example (beware of lenses) :

class Indexable m k a where
  at :: k -> Lens' m (Maybe a)

The null element and set union belong to the Monoid typeclass (where mappend == union). In this light, set difference could also be implemented in its own typeclass Differentiable (which I'm sure already exists in dozens of Haskell libraries) and we would have total compatibility with imperative languages.

Haskell, by virtue of being designed by mathematicians and the like, doesn't employ the same vocabulary as most other languages, but rest assured, it doesn't mean that it's not a practical language in addition to being an awesome one :-)


Laws. A good typeclass has laws. A great typeclass has enough parametricity so that it's laws are "theorems for free". A typeclass without laws is just ad-hoc name overloading.

Also, check out classy-prelude and Edison-API.


You have typeclasses for different collection aspects:

  1. composition: Monoid (module Data.Monoid)

  2. sequential control: Applicative, Monad (modules Control.Applicative, Control.Monad)

  3. sequential composition: Alternative, MonadPlus (modules Control.Applicative, Control.Monad)

  4. non-sequential mapping and reduction: Functor (mod. Data.Functor), Foldable (mod. Data.Foldable)

  5. sequential mapping and reduction: Traversable (module Data.Traversable)

  6. serialisation: Binary (mod. Data.Binary)

  7. comparison: Eq, Ord (mod. Data.Eq, Data.Ord)

  8. textualisation: Show, Read

  9. deep evaluation (to Normal Form): NFData (mod. Control.DeepSeq)

  10. generic datatype traversability: Data (mod. Data.Data)

Except that monomorphic collections (ByteString, IntSet, Text) cannot implement Functor and Foldable (they require type arity == 1 (Kind: * -> *))

Also neither (Set a) implements Functor.

The package mono-traversable redefines some classes without the monomorphic types exclusion.

Update. There is an attempt to put most functions in typeclasses with the packages mono-traversable and classy-prelude.

library ref, platform

ReferenceURL : https://stackoverflow.com/questions/25191659/why-is-haskell-missing-obvious-typeclasses

반응형