Haskell의 지수


91

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

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

답변:


130

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

(^) :: (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.


31

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에서 허용하는 것보다 더 영리해야하기 때문입니다.


4
이것이 구현 불가능하다는 진술이 여전히 사실입니까? IIRC, haskell에는 다중 매개 변수 유형 클래스의 두 번째 매개 변수가 첫 번째 매개 변수에 의해 엄격하게 결정되는 옵션이 있습니다. 이 외에 해결할 수없는 또 다른 문제가 있습니까?
RussellStewart 2014 년

2
@singular 여전히 사실입니다. 예를 들어 첫 번째 인수는 두 번째 인수를 결정하지 않습니다. 예를 들어 지수가 IntInteger. 이 세 가지 인스턴스 선언을 가질 수 있으려면 인스턴스 확인에서 역 추적을 사용해야하며 Haskell 컴파일러는이를 구현하지 않습니다.
8

7
합니까 "형 시스템은 강력한 충분하지 않다" 인수는 여전히 2015 월으로 개최?
Erik Kaplun 2015 년

3
내가 제안한 방식으로 작성할 수는 없지만 인코딩하는 방법이있을 수 있습니다.
8

2
새로운 하스켈 보고서는 2010 년부터 올 것처럼 @ErikAllik 아마, 표준 하스켈의 경우와
마틴 Capodici

10

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

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

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


4

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

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


4
Haskell 유형의 사고 방식이 덕 타이핑의 반대라는 점에 전적으로 동의하지 않습니다. Haskell 유형 클래스는 오리 입력과 매우 유사합니다. class Duck a where quack :: a -> Quack오리에 대해 우리가 기대하는 것을 정의하고 각 인스턴스는 오리처럼 행동 할 수있는 것을 지정합니다.
augustss

9
@augustss 나는 당신이 어디에서 왔는지 봅니다. 그러나 오리 타이핑의 비공식적 모토는 "오리처럼 보이고, 오리처럼 행동하고, 오리처럼 꽥꽥 거리는 경우, 그것은 오리입니다."입니다. Haskell에서는 인스턴스로 선언되지 않는 한 오리가 아닙니다 Duck.
Dan Burton

1
사실이지만 하스켈에서 기대했던 것입니다. 오리를 원하는 것은 무엇이든 만들 수 있지만, 그것에 대해 명시 적이어야합니다. 오리가되기 위해 요청하지 않은 것을 착각하고 싶지 않습니다.
8

Haskell의 작업 방식과 덕 타이핑에는 더 구체적인 차이가 있습니다. 예, 모든 유형에 Duck 클래스를 부여 할 수 있지만 이는 Duck이 아닙니다. 꽥꽥 거리는 능력이 있지만, 구체적으로 어떤 유형이든 여전히 그렇습니다. 여전히 Ducks 목록을 가질 수 없습니다. Ducks 목록을 받아들이고 다양한 유형의 Duck 클래스를 혼합 및 일치시키는 기능은 작동하지 않습니다. 이 점에서 Haskell은 "오리처럼 꽥꽥 거리면 오리입니다."라고 말하는 것을 허용하지 않습니다. Haskell에서 모든 Duck은 동일한 유형의 Quacker 여야합니다. 이것은 실제로 오리 타이핑과는 상당히 다릅니다.
mmachenry

혼합 오리 목록을 가질 수 있지만 Existential Quantification의 확장이 필요합니다.
Bolpat
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.