Haskellの数値変換（wiki.haskell.orgからの邦訳）

# 訳者まえがき
Haskellには初心者殺しの関所が幾つもありますが、その一つに

- 簡単な四則演算すら型が合わずコンパイルできない

があります。
この問題を解決するためにアチコチの本やサイトを読みましたが、結局一番分かりやすかったのは[wiki.haskell.orgの記事](https://wiki.haskell.org/Converting_numbers)でした。
自分のために翻訳したものを公開します（最後に独自に数値型の階層と変換関数の一覧もまとめています）。
日本語版公開にあたっては[HaskellWiki:Copyrights](https://wiki.haskell.org/HaskellWiki:Copyrights)を参照し、問題ないとの判断をしていますが、万が一権利侵害等がありましたら、ご指摘ください。許諾等の処理が完了するまで公開を中止します。

# 本文
以下は[Converting numbers](https://wiki.haskell.org/Converting_numbers)の日本語訳です。

Haskellにおける数値型間の変換は明示的に行う必要があります。
これは他の多くの伝統的言語（CやJavaなど)で暗黙にキャストが行われるのとは異なります。

## 1. 整数型との間の変換

整数(`Integral`)型には整数だけが含まれます（分数は含まれません）
最も一般的に使われるのは次の二つの型です。

- `Integer`は他の言語ではしばしば「bignum」または「big-integer」と呼ばれる任意精度の整数です。
- `Int`は固定幅のマシン固有の整数で、最小保証範囲は-2^29〜2^29-1ですが、実際にはもっと大きくなることが多いです。GHCコンパイラのx86-64バージョンでは、符号付64ビット整数を扱うことができます。

整数型からの変換に主に使われるのは`fromIntegral`です。
任意の整数型を任意の数字（`Num`)型（`Int`,`Integer`,`Rational`,`Double`)に変換します。

```整数型数値の変換.hs
fromIntegral :: (Num b, Integral a) => a -> b
```
例えば`Int`である値`n`のルートをとる場合、単純に`sqrt n`とは書けません。なぜなら`sqrt`は浮動小数点数にのみ適用可能だからです。
したがって、代わりに`sqrt (fromIntegral n)`と明示的に`n`を`Num`型に変換し、浮動小数点の値に降りていけるようにする必要があります。

```fromIntegerはIntegerから任意の数字型への変換の特殊ケース.hs
fromInteger :: Num a => Integer -> a
```

```同じように整数型からIntegerへの変換の特殊ケース.hs
toInteger:: Integral a => a -> Integer
```
## 2. 実数型と実数分数型(有理数型)間の変換
実数分数(`RealFrac`tional)型は、整数と分数のどちらも属することができます。
最も一般的に使われる型は次のとおり。

- `Rational`は任意精度の分数
- `Double`は倍精度の浮動小数点数

実数(`Real`)型は整数(`Integral`)型と実数分数(RealFrac)型の両方を含みます。
型名の"real"は複素数が除外されていることを示しています。
実数(`Real`)型からの変換に使われるのは`realToFrac`で、任意の実数型を任意の分数型(`Fractional`)型（`Rational,Double`の属する型)に変換します。

```realToFrac.hs
realToFrac:: (Real a, Fractional b) => a -> b
```

`realToFrac`は`RealFrac`型間の変換にも使うことができます。
(後述のとおり、`realToFrac`を浮動小数点型間の変換に使うことは避けてください）

```Rationalから分数への変換.hs
fromRational :: Fractional a => Rational -> a
```
```実数から有理数（Rational)への変換?.hs
toRational :: Real a => a -> Rational
```
## 3. 実数分数から整数への変換 
整数型は非整数を表すことができないので、これは本質的に損失のある変換です。 変換方法に応じて、次のいずれかを選択することができます：

```非整数→整数?.hs
ceiling  :: (RealFrac a, Integral b) => a -> b
floor    :: (RealFrac a, Integral b) => a -> b
truncate :: (RealFrac a, Integral b) => a -> b
round    :: (RealFrac a, Integral b) => a -> b
```
## 4. 異なる精度の浮動小数点間の変換
`Float`と`Double`の間の変換は、`GHC.Float`モジュールのGHC固有の関数を使用します。

```GHC.Float.hs
float2Double :: Float -> Double
double2Float :: Double -> Float
```
`RealToFrac`を使用して浮動小数点型同志の変換は避けてください。中間型である`Rational`は、無限大またはNaNなどの例外的な値を表すことができません。 GHCチケット＃3676を参照してください。

## 5. 自動変換　
人々は何度も数値間の自動変換を要求しますが、これは通常良くない考えとされています。詳細は[一般的な数値型に関する考え](https://wiki.haskell.org/Generic_number_type)を参照してください。

## 6. 例

2つの座標系の間で変換するいくつかの関数を記述しようとしています。 
`coord1`を呼び出す最初の座標系は、左上が`（0、0）`で始まり、右下が`（500,500）`で終わります。 
`coord1`の座標は`（Int、Int）`型です。 
`coord2`と呼ばれる第2の座標系は、左下が`（0.0、0.0）`で始まり、右上の`（1.0,1.0）`で終わります。 
`coord2`の座標は、`（Float、Float）`型です。 
型チェックが通るように以下の2つの関数を書き換えます。

```このままだとコンパイルは通らない.hs
coord1ToCoord2 :: (Int, Int) -> (Float, Float)
coord1ToCoord2 (x, y) = (x/500, (500-y)/500)
 
coord2ToCoord1 :: (Float, Float) -> (Int, Int)
coord2ToCoord1 (x, y) = (500/(1/x), 500 - 500/(1/y))
```
```こうなって欲しい.hs
 coord1ToCoord2 (0, 0) -> (0.0, 1.0)
 coord1ToCoord2 (250, 250) -> (0.5, 0.5)
 coord1ToCoord2 (350, 350) -> (0.7, 0.3)
 coord1ToCoord2 (500, 500) -> (1.0, 0.0)
 
 coord2ToCoord1 (0.0, 0.0) -> (0, 500)
 coord2ToCoord1 (0.5, 0.5) -> (250, 250)
 coord2ToCoord1 (0.7, 0.7) -> (350, 150)
 coord2ToCoord1 (1.0, 1.0) -> (500, 0)
```
解法は`fromIntegral`と`round`を使うことです。

```コンパイル通る例.hs
coord1ToCoord2 :: (Int, Int) -> (Float, Float)
coord1ToCoord2 (x, y) = (fromIntegral x/500, (500 - fromIntegral y)/500)
 
coord2ToCoord1 :: (Float, Float) -> (Int, Int)
coord2ToCoord1 (x, y) = (round (500 * x), round (500 - 500 * y))
```

# 訳者あとがき
特にクラス名の訳語は最適なものが見つからないので、標準的な訳語があるものは教えていただきたいです。

この記事の理解を深めるため、私の書いた図を二つ付けておきます。（かなり昔に作ったため、陳腐化や間違いがあればご指摘くださると助かります）
### a. 数値クラスの階層関係
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60888/33d3f1ee-ee82-ea39-887d-004c07aa1e54.png)

参考：hackage , Haskell Language Report 2010

### b. 数値型間の変換表
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60888/84fb0be5-71ea-4806-5b00-50e8435bd2af.png)

参考：「Real World Haskell」6章 6.4.4数値型　表6-4