Haskell Language
유형 클래스
수색…
소개
하스켈의 유형 표시는 해당 유형의 정의와 별도로 유형과 연관된 비헤이비어를 정의하는 수단입니다. 말하자면, 자바에서는 타입 정의의 일부로 동작을 정의하는 반면, 하스켈은이 두 가지를 분리 된 상태로 유지합니다.
Haskell의 base
패키지에 이미 정의 된 여러 가지 유형이 있습니다. 이들 사이의 관계는 아래 비고 섹션에 설명되어 있습니다.
비고
Typeclassopedia 기사에서 가져온 다음 다이어그램은 하스켈의 다양한 유형 간 관계를 보여줍니다.
어쩌면 펑터 클래스
Haskell에서 데이터 타입은 함수처럼 인자를 가질 수있다. Maybe
유형을 예로 들어 보겠습니다.
Maybe
실패 나 그 가능성에 대한 생각을 표현할 수있는 매우 유용한 유형 일 것입니다. 즉, 계산이 실패 할 가능성이있는 경우 Maybe
형식을 사용합니다. Maybe
다른 유형의 래퍼처럼 작동하여 추가 기능을 제공 할 수 있습니다.
실제 선언은 매우 간단합니다.
Maybe a = Just a | Nothing
이것이 의미하는 바는 Maybe
는 성공을 나타내는 Just
와 실패를 나타내는 Nothing
두 가지 형태로 제공된다는 것입니다. Just
의 유형을 결정 하나 개의 인수 소요 Maybe
하고, Nothing
없음을지지 않습니다. 예를 들어 Just "foo"
값에는 Maybe String
유형이 있습니다.이 유형은 Maybe
기능이 추가 된 문자열 유형입니다. 값 Nothing
입력이없는 Maybe a
여기서 a
어떤 유형이 될 수 있습니다.
추가 기능을 제공하기 위해 유형을 래핑하는이 아이디어는 매우 유용하며 단순한 Maybe
이상에 적용 할 수 있습니다. 다른 예로는 서로 다른 기능을 제공하는 Either
, IO
및 List 유형이 있습니다. 그러나 이러한 모든 래퍼 유형에 공통적 인 몇 가지 작업과 기능이 있습니다. 가장 주목할만한 것은 캡슐화 된 값을 수정할 수있는 기능입니다.
이러한 종류의 유형을 값을 가질 수있는 상자로 생각하는 것이 일반적입니다. 서로 다른 상자는 다른 값을 가지며 다른 일을하지만, 그 안에있는 내용에 액세스 할 수 없으면 아무 것도 유용하지 않습니다.
이 아이디어를 캡슐화하기 위해 Haskell에는 Functor
라는 표준 typeclass가 있습니다. 그것은 다음과 같이 정의됩니다.
class Functor f where
fmap :: (a -> b) -> f a -> f b
알 수 fmap
클래스에는 두 개의 인수로 이루어진 단일 함수 fmap
있습니다. 첫 번째 인수는, 한 유형에서 다른 함수 , 서로, a
b
. 두 번째 인수는 입력 값 함유하는 펑 (래퍼 형)이다 a
. b
유형의 값을 포함하는 펑터 (랩퍼 유형)를 리턴합니다.
간단히 말해서, fmap
은 함수를 취해서 functor 내부의 값에 적용됩니다. Functor
클래스의 멤버가 될 수있는 유일한 유형의 함수이지만, 매우 유용합니다. 보다 구체적인 응용 프로그램이있는 펑터에서 작동하는 함수는 Applicative
및 Monad
에서 찾을 수 있습니다.
Type 클래스 상속 : Ord 타입 클래스
Haskell은 클래스 확장 개념을 지원한다. 예를 들어, Ord
클래스는 Eq
모든 연산을 상속하지만 값 사이에 Ordering
을 반환하는 compare
함수도 있습니다. Ord
는 공통 순서 비교 연산자와 min
메소드 및 max
메소드를 포함 할 수도 있습니다.
=>
표기법은 함수 서명에서와 동일한 의미를 가지며 Ord
를 구현하기 위해 Eq
를 구현하기 위해 유형 a
가 필요합니다.
data Ordering = EQ | LT | GT
class Eq a => Ord a where
compare :: Ord a => a -> a -> Ordering
(<) :: Ord a => a -> a -> Bool
(<=) :: Ord a => a -> a -> Bool
(>) :: Ord a => a -> a -> Bool
(>=) :: Ord a => a -> a -> Bool
min :: Ord a => a -> a -> a
max :: Ord a => a -> a -> a
compare
다음의 모든 메소드는 여러 가지 방법으로 파생 될 수 있습니다.
x < y = compare x y == LT
x <= y = x < y || x == y -- Note the use of (==) inherited from Eq
x > y = not (x <= y)
x >= y = not (x < y)
min x y = case compare x y of
EQ -> x
LT -> x
GT -> y
max x y = case compare x y of
EQ -> x
LT -> y
GT -> x
자체적으로 확장하는 타입 클래스 Ord
는 적어도 compare
메소드 또는 (<=)
메소드 자체를 구현해야하며, 이는 상속 된 상속 격자를 빌드합니다.
Eq
Prelude의 함수와 IO
제외한 모든 기본 데이터 유형 ( Int
, String
, Eq a => [a]
)은 Eq
. 유형이 Eq
인스턴스화하는 경우 값 또는 구조적 동일성에 대해 두 값을 비교하는 방법을 알고 있음을 의미합니다.
> 3 == 2
False
> 3 == 3
True
필수 메소드
-
(==) :: Eq a => a -> a -> Boolean
또는(/=) :: Eq a => a -> a -> Boolean
(하나만 구현하면 다른 기본값은 정의 된 것)
정의
-
(==) :: Eq a => a -> a -> Boolean
-
(/=) :: Eq a => a -> a -> Boolean
직접 슈퍼 클래스
없음
주목할만한 하위 클래스
Ord
인스턴스 생성 유형 Ord
에는 Int
, String
및 [a]
(예 : Ord
인스턴스 a
있는 유형 Ord a
경우)가 포함됩니다. 형식이 Ord
인스턴스화하는 경우 해당 유형의 값의 "자연스러운"정렬을 의미합니다. 참고로, 종종 유형의 "자연적인"순서에 대한 가능한 많은 선택이 있으며 Ord
는 우리에게 하나를 선호하도록 강요합니다.
Ord
는 표준 (<=)
, (<)
, (>)
, (>=)
연산자를 제공하지만 사용자 정의 대수 데이터 형식을 사용하여 모두 흥미롭게 정의합니다
data Ordering = LT | EQ | GT
compare :: Ord a => a -> a -> Ordering
필수 메소드
-
compare :: Ord a => a -> a -> Ordering
또는(<=) :: Ord a => a -> a -> Boolean
(표준의 기본compare
메소드는 구현시(<=)
)
정의
-
compare :: Ord a => a -> a -> Ordering
-
(<=) :: Ord a => a -> a -> Boolean
-
(<) :: Ord a => a -> a -> Boolean
-
(>=) :: Ord a => a -> a -> Boolean
-
(>) :: Ord a => a -> a -> Boolean
-
min :: Ord a => a -> a -> a
-
max :: Ord a => a -> a -> a
직접 슈퍼 클래스
모노 노이드
Monoid
는 Monoid
반환 값을 포함한 목록, 숫자 및 함수를 포함합니다. 인스턴스화 Monoid
연관 이진 동작 지원해야 타입 ( mappend
또는 (<>)
)의 값을 결합하고, 특별한 "제로"값 (갖는 mempty
)와 같은 그것의 값을 조합하여, 그 값을 변경하지 않는 것을 :
mempty <> x == x
x <> mempty == x
x <> (y <> z) == (x <> y) <> z
직관적으로 Monoid
유형은 값을 함께 추가 할 수 있다는 점에서 "목록과 유사"합니다. 또는 Monoid
유형은 순서에 대해 신경을 쓰지만 그룹에는 신경 쓰지 않는 값의 연속으로 생각할 수 있습니다. 예를 들어, 이진 트리는 Monoid
이지만 Monoid
연산을 사용하면 분기 구조를 볼 수없고 값의 순회 만 볼 수 있습니다 ( Foldable
및 Traversable
참조).
필수 메소드
-
mempty :: Monoid m => m
-
mappend :: Monoid m => m -> m -> m
직접 슈퍼 클래스
없음
숫자
숫자 유형에 대한 가장 일반적인 클래스입니다. 즉, 반지 에 대해 더 정확하게 말하면, 보통의 의미로 덧셈 및 뺄셈을 할 수 있지만 반드시 나눌 수는 없습니다.
이 클래스에는 Integer
형 ( Int
, Integer
, Word32
등)과 소수 형 ( Double
, Rational
, 복소수 등)이 모두 포함됩니다. 유한 타입의 경우, 의미론은 일반적으로 모듈러 산술 , 즉 오버 플로우 및 언더 플로우 † 로 이해됩니다.
수치 클래스에 대한 규칙은 모나드 또는 모노로이드 법칙이나 평등 비교법 보다 훨씬 엄격하게 적용됩니다. 특히 부동 소수점 숫자는 일반적으로 대략적인 의미로만 법칙을 준수합니다.
방법
fromInteger :: Num a => Integer -> a
. 정수를 일반 숫자 형식으로 변환합니다 (필요한 경우 범위를 둘러 쌉니다). Haskell 숫자 리터럴 은 주위의 일반적인 변환과 함께 단일Integer
리터럴로 이해할 수 있으므로Int
문맥과Complex Double
설정에서 리터럴5
를 사용할 수 있습니다.(+) :: Num a => a -> a -> a
. 표준 추가, 일반적으로 associative 및 commutative로 이해, 즉,a + (b + c) ≡ (a + b) + c a + b ≡ b + a
(-) :: Num a => a -> a -> a
. 빼기 (덧셈의 역함수) :(a - b) + b ≡ (a + b) - b ≡ a
(*) :: Num a => a -> a -> a
. 곱셈 (multiplication), 덧셈을 통해 분포되는 연관 연산 :a * (b * c) ≡ (a * b) * c a * (b + c) ≡ a * b + a * c
가장 일반적인 인스턴스의 경우 곱셈도 교환 가능하지만 이것은 필수 조건은 아닙니다.
negate :: Num a => a -> a
. 단항 부정 연산자의 전체 이름입니다.-1
은negate 1
문법적 설탕입니다.-a ≡ negate a ≡ 0 - a
abs :: Num a => a -> a
. 절대 값 함수는 항상 동일한 크기의 음이 아닌 결과를 제공합니다.abs (-a) ≡ abs a abs (abs a) ≡ abs a
abs a ≡ 0
경우에만 발생한다a ≡ 0
.실제 유형의 경우 음수가 아닌 의미는 분명합니다. 항상
abs a >= 0
입니다. 복합 등 유형 그러나 결과, 잘 정의 된 순서가없는abs
항상 (즉,도 부정하지 않고 문자 그대로 하나의 숫자로 기록 될 수있는 번호를 알려) 실제 부분 집합 ‡에서 거짓말을한다.signum :: Num a => a -> a
. sign 함수는 이름에 따라 인수의 부호에 따라-1
또는1
만 산출합니다. 실제로 그것은 0이 아닌 실수에 대해서만 유효합니다. 일반적으로signum
은 정규화 함수로 더 잘 이해됩니다.abs (signum a) ≡ 1 -- unless a≡0 signum a * abs a ≡ a -- This is required to be true for all Num instances
Haskell 2010 보고서의 6.4.4 절 에는 명시 적으로 유효한
Num
인스턴스를 보유하기위한 최종 동등성이 명시 적으로 필요합니다.
일부 라이브러리, 특히 선형 및 hmatrix 는 Num
클래스가 무엇인지에 대해 훨씬 이해하기 쉽지 않습니다 . 산술 연산자를 과부하하는 방법 으로 취급합니다. +
와 -
는 매우 간단하지만, 다른 방법을 사용할 때 이미 *
가 번거로워집니다. 예를 들어, *
는 행렬 곱셈 또는 요소 별 곱셈을 의미합니까?
논 - 숫자 인스턴스를 정의하는 것은 틀림없이 나쁜 생각입니다. VectorSpace
와 같은 전용 클래스를 고려하십시오.
† 특히, 부호없는 타입의 "네가티브"는 큰 양수로 둘러 (-4 :: Word32) == 4294967292
예 : (-4 :: Word32) == 4294967292
.
이 널리 충족되지 ‡ : 벡터 유형은 실제 집합이 없습니다. 논쟁의 여지가있는 Num
인스턴스는 일반적으로 abs
와 signum
요소별로 정의합니다. 수학적으로 말하면 실제로 이해가되지 않습니다.