[haskell] Haskell의 지수

누군가 Haskell Prelude가 지수화를 위해 두 개의 개별 함수를 정의하는 이유를 말해 줄 수 있습니까 (예 : ^and **)? 나는 타입 시스템이 이런 종류의 중복을 제거해야한다고 생각했습니다.

Prelude> 2^2
4
Prelude> 4**0.5
2.0



답변

실제로 세 가지 지수 연산자가 있습니다 : (^), (^^)(**). ^음이 아닌 적분 지수, ^^정수 지수 및 **부동 소수점 지수입니다.

(^) :: (Num a, Integral b) => a -> b -> a
(^^) :: (Fractional a, Integral b) => a -> b -> a
(**) :: Floating a => a -> a -> a

그 이유는 유형 안전성 때문입니다. 수치 연산의 결과는 일반적으로 입력 인수와 동일한 유형을 갖습니다. 그러나를 Int부동 소수점 거듭 제곱으로 올리고 유형 결과를 얻을 수는 없습니다 Int. 따라서 유형 시스템은이 작업을 방지합니다 (1::Int) ** 0.5. 유형 오류가 발생합니다. 동일은 간다 (1::Int) ^^ (-1).

이것을 넣는 또 다른 방법 : Num유형은 아래에 닫히고 ^(승법 역수를 가질 필요는 없음), Fractional유형은 아래에 닫히고 ^^, Floating유형은 아래에 닫힙니다 **. 에 대한 Fractional인스턴스 가 없기 때문에 Int음의 거듭 제곱으로 올릴 수 없습니다.

이상적으로의 두 번째 인수는 ^음이 아니도록 정적으로 제한됩니다 (현재 1 ^ (-2)런타임 예외 발생). 그러나 Prelude.


답변

Haskell의 유형 시스템은 세 가지 지수 연산자를 하나로 표현할만큼 강력하지 않습니다. 정말로 원하는 것은 다음과 같습니다.

class Exp a b where (^) :: a -> b -> a
instance (Num a,        Integral b) => Exp a b where ... -- current ^
instance (Fractional a, Integral b) => Exp a b where ... -- current ^^
instance (Floating a,   Floating b) => Exp a b where ... -- current **

다중 매개 변수 유형 클래스 확장을 켜도 실제로 작동하지 않습니다. 인스턴스 선택이 현재 Haskell에서 허용하는 것보다 더 영리해야하기 때문입니다.


답변

두 개의 연산자를 정의하지 않고 세 개를 정의합니다! 보고서에서 :

세 가지 두 인수 지수 연산이 있습니다. ( ^) 임의의 수를 음이 아닌 정수 거듭 제곱으로, ( ^^) 분수를 임의의 정수 거듭 제곱으로, ( **) 두 개의 부동 소수점 인수를 취합니다. x^0또는 의 값은 0을 포함하여 x^^0모든 x에 대해 1입니다 . 0**y정의되지 않았습니다.

즉, 세 가지 다른 알고리즘이 있으며 그 중 두 개는 정확한 결과 ( ^^^)를 **제공하고 대략적인 결과 를 제공합니다. 사용할 연산자를 선택하여 호출 할 알고리즘을 선택합니다.


답변

^두 번째 인수가 Integral. 내가 착각하지 않았다면 적분 지수로 작업하는 것을 안다면 구현이 더 효율적일 수 있습니다. 또한 다음과 같은 것을 원한다면2 ^ (1.234) 의 밑이 적분, 2 인 경우에도, 당신의 결과는 분명히 분수 일 것입니다. 지수 함수에 들어가고 나가는 유형을보다 엄격하게 제어 할 수 있도록 더 많은 옵션이 있습니다.

Haskell의 유형 시스템은 C, Python 또는 Lisp와 같은 다른 유형 시스템과 동일한 목표를 가지고 있지 않습니다. 덕 타이핑은 (거의) 하스켈 사고 방식과 반대입니다.


답변