「混ぜられない数」をHaskell/GHCの型を使って手軽につくる

1. はじめに
============

Haskell/GHCの型システムを使って、「混ぜることのできない数」のグループを手軽に作る方法を紹介します。
Haskellの基本的な機能と、GHC拡張を１つだけ使用しています。

なお、ここで紹介する方法は、Don Stewartさんが昔に、"Haskell in the Large"という資料（現在、オリジナル資料はリンク切れ）で紹介していたものを元にしています。
また、本記事で出てくるnewtype宣言やphantom型や数値型については、以下の記事などが参考になります。

* [すごいH本で見落としがちだが実は重要な機能：newtype](https://qiita.com/HirotoShioi/items/70cd235e93dee99bf8e8)
* [本当はすごい newtype](https://speakerdeck.com/konn/ben-dang-hasugoi-newtype)
* [で、出たー！幽霊型だー！(Phantom Type)](https://qiita.com/HirotoShioi/items/3444e215070144b8ca0f)
* [Haskellらしさって？「型」と「関数」の基本を解説！ （数値型と型クラスについて簡単に）](https://employment.en-japan.com/engineerhub/entry/2017/08/25/110000#%E6%95%B0%E5%80%A4%E5%9E%8B%E3%81%A8%E5%9E%8B%E3%82%AF%E3%83%A9%E3%82%B9%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6%E7%B0%A1%E5%8D%98%E3%81%AB)


では、順に試しながら機能を追加していきます。
最初に基本的な型を包む独自の数値型をつくり、その後、それらを互いに区別できるように改善します。
（なお、各節に対応する短いソースファイルを[GitHubのリポジトリ](https://github.com/takenobu-hs/haskell-newtype-phantom-example)に置いておきました。）


2. まず、独自の数値型の基本を作る
==================================

まずは、基本的な独自の数値型を作ります。
以下、GHCの対話環境であるghciコマンド上で試していきます。（本記事では、`ghci>`の表記により、ghciコマンドの入力プロンプトを表しています。ghciのデフォルトでは、入力プロンプトを`Prelude>`と表示しています。）


## 2.1 まずは、newtype宣言で独自の数値型を作る

まずは次のように、`newtype`宣言を使用して、既存の`Int`型を包む新しい型`Value`を作ってみます。[^newtype1]

```
ghci> newtype Value = Val Int
```

新しく作った型を試してみましょう。`Value`型の値（`Val 1`）を作って、変数`x`に対応づけてみます。

```
ghci> x = Val 1
```

変数`x`の型を、ghciの`:type`コマンドを使って確認してみます。

```
ghci> :type x
x :: Value
```

変数`x`は、`Value`型として認識されています。新しい、独自の数値型を作れました。


## 2.2 独自の数値型を、表示や、同値比較や、大小比較できるようにする

続いて、独自に作った数値型を、少し便利にしてみます。
Haskellのderiving(自動導出)機能を使って、表示(`Show`)、同値比較(`Eq`)、大小比較(`Ord`)のための関数を、独自に作った数値型に導入します。[^newtype2]

以下のように、`newtype`宣言に`deriving (Show, Eq, Ord)`節を追加します。

```
ghci> newtype Value = Val Int deriving (Show, Eq, Ord)
```

試してみます。まずは、テストのために先程と同様に、変数`x`を`Value`型の値に割り当てておきます。

```
ghci> x = Val 2
```

`Show`クラスをderivingしているので、次のように、変数の値を表示できるようになっています。

```
ghci> x
Val 2
```

`Eq`と`Ord`クラスをderivingしているので、`==`や`<`演算子を使えるようになっています。これにより、同値比較や大小比較ができるようになります。

```
ghci> x == x
True

ghci> x < x
False
```


## 2.3 独自の数値型を、加減乗算できるようにする

さらに、独自に作った数値型を、基本的な算術演算（加減乗算）ができるようにしていきます。

このために１つだけ、GHC拡張を使用します。まず、ghciに次のように入力して、`GeneralizedNewtypeDeriving`言語拡張を有効にします。[^newtype3a]
これにより、`newtype`宣言の`deriving`節に、`Show`や`Eq`などの基本的な型クラス以外をも追加できるようになります。[^newtype3b]

```
ghci> :set -XGeneralizedNewtypeDeriving
```

さらに以下のように、加減算などの算術演算が定義された`Num`クラスを、`deriving`節に追加します。[^newtype3c]

```
ghci> newtype Value = Val Int deriving (Show, Eq, Ord, Num)
```

試してみます。先程と同様に、変数`x`を`Value`型の値に割り当てておきます。

```
ghci> x = Val 3
```

`Num`クラスをderivingしているので、作成した型において、`+`や`*`の演算子を使用できるようになっています。（つまり、自分で`+`や`*`に相当する演算のコードを実装することなく、`+`や`*`の機能を実現できます。`+`や`*`に相当するコードは、自動で導出(deriving)されます。便利ですね。）

```
ghci> x + x
Val 6

ghci> x * 3
Val 9
```

なお、`Num`クラスをderivingしているので、`fromInteger`関数をも暗黙的に使用できるようになります。
これにより、型が明確であれば、値コンストラクタの`Val`なしで、直接的に数値リテラルのみを記述できます。
（つまり、`x = Val 1`でなく、`x = 1`のように記述できます。[^newtype3d]）

```
ghci> x = 1 :: Value
```

以上のようにして、整数型(`Int`）の数値のように振る舞う独自の型`Value`型をつくれました。

参考までに、以上の内容をプログラムファイルの形でまとめてみると、次のようになります。
わずかこれだけの記述で、整数型のように振る舞う独自の型を、演算子や関数などを別途自作することなく実現できます。

```Haskell:2.3.newtype.hs
{-# LANGUAGE GeneralizedNewtypeDeriving #-}

newtype Value = Val Int deriving (Show, Eq, Ord, Num)
```


3. さらに、独自の数値型を、互いに区別できるようにする
=======================================================

続いて、独自の数値型を、互いに区別できるようにしてみます。
例えば、数値のグループの例として、「通貨の円を表すグループ」と「通貨のUSドルを表すグループ」を想定して、それぞれを区別して扱えるようにしてみます。

## 3.1 まずは、phantom型を使って、独自の型を互いに区別できる仕組みを入れる

これまでの`Value`型を改造し、次のように、左辺を`Value a`に変更します。
これまでの定義との違いは、`a`が追加されていることだけです。

```
ghci> newtype Value a = Val Int deriving (Show, Eq, Ord, Num)
```

この`a`は型変数です。ただし、右辺の定義には現れない型変数です。右辺に現れない不思議な型の表現のため、phantom型（ファントム型、幽霊型）と呼ばれます。

定義した`Value a`型を使ってみましょう。

```
ghci> x = 10 :: Value a

ghci> :type x
x :: Value a

ghci> x + 1
Val 11
```

使い勝手は、これまでと同じですね。

さらに、型変数`a`の位置には、次のように任意の具体的な型を記述することもできます。

```
ghci> y = 1 :: Value Float
ghci> z = 1 :: Value Char
```

とても紛らわしいのですが、上記で`a`の位置に記述した型（`Float`や`Char`）は、「型の目印」として使用されるだけで、式の値が`Float`や`Char`になるわけではありません。
式の値は、あくまで、`Val Int`です。つまり、`Int`型を値コンストラクタ`Val`で包んだものです。

しかし、この「型の目印」の特徴を使うことで、それぞれの値のグループを区別することができます。


## 3.2 さらに、区別のための補助的なデータ型を用意する

上記のように、`Value a`型を互いに区別するために、型変数`a`の位置に既存の型（`Float`や`Char`）を用いることもできます。
しかし、既存の意味を持った`Float`や`Char`を使用すると誤解のもとなので、データ区別用の補助的なデータ型を用意してみましょう。

次のように`data`宣言を使用して、補助的な２つのデータ型（`ValYen`と`ValUSD`）を用意します。ここでは、型の世界での区別のみに使用するため、右辺の値を持たないデータ型として定義しています。

それでは、3.1節の`newtype`宣言に加えて、次の２行も入力します。

```
ghci> data ValYen
ghci> data ValUSD
```

この補助的なデータ型を使って、`Value a`型の`a`をそれぞれ具体化してみましょう。以下のように使います。

```
ghci> y = 100 :: Value ValYen
ghci> z = 1 :: Value ValUSD
```

`Value Float`や`Value Char`よりは、分かりやすくなりました。
では、数値のように扱えるか試してみます。

```
ghci> y * 2
Val 200

ghci> z * 2
Val 2

ghci> y + y
Val 200

ghci> z + z
Val 2
```
これまでの様に、数値のように使えました。

さらにここで、この記事において**最も重要な特徴**である、「混ぜられないこと」について試してみます。
上記の変数`y`と変数`z`は、各々を数値のように扱えますが、互いを混ぜることはできません。以下のように誤って混ぜてしまった場合には、実行時ではなくコンパイル時に、適切に型エラーとして検出してくれます。

```
ghci> y + z

<interactive>:11:5: error:
    • Couldn't match type ‘ValUSD’ with ‘ValYen’
      Expected type: Value ValYen
        Actual type: Value ValUSD
    • In the second argument of ‘(+)’, namely ‘z’
      In the expression: y + z
      In an equation for ‘it’: it = y + z
```

このようにして、数値のように使うことができ、かつ、各々のグループを混ぜては使えない、数値のような型を作ることができました。


## 3.3 最後に、データ型を短く書けるように別名をつける

さらに、型の使い勝手を少し良くしてみます。なお、この節の内容は必須ではありません。
`Value ValYen`型や`Value ValUSD`型について、`type`宣言を用いることで、より短い別名（シノニム）を付けてみます。

3.1節の`newtype`宣言と、3.2節の`data`宣言に加えて、さらに次の２行を入力します。

```
ghci> type Yen = Value ValYen
ghci> type USD = Value ValUSD
```

これにより、各々の型名を、`Value ValYen`ではなく、`Yen`のように簡潔に記述できます。

```
ghci> y = 100 :: Yen
ghci> z = 1 :: USD
```

数値のように扱えるか試してみます。

```
ghci> y + 2*y
Val 300

ghci> z * 2 + 1
Val 3
```

これまでの様に、数値のように使えました。

なお、Haskellの型推論の機能により、独自に作ったデータ型も正しく伝搬していきます。以下のように、変数`y`を用いた式の型は、変数`y2`に正しく伝わります。ここでは、変数`y`の型`Yen`が、変数`y2`に伝わっています。

```
ghci> y2 = y + 30

ghci> :type y2
y2 :: Yen
```

そして最も重要な特徴ですが、異なる数のグループを混ぜて使った場合には、コンパイル時に正しく型エラーとして検出できます。

```
ghci> y + z

<interactive>:17:5: error:
    • Couldn't match type ‘ValUSD’ with ‘ValYen’
      Expected type: Yen
        Actual type: USD
    • In the second argument of ‘(+)’, namely ‘z’
      In the expression: y + z
      In an equation for ‘it’: it = y + z
```

上記では、`y`は`Yen`型であり、`z`は`USD`型です。演算子`+`は２つの型が同じであることを要求しており、このように型が混在している場合には、エラーとして検出できます。

以上の内容を、ファイルの形でまとめると次のようになります。

```Haskell:3.3.phantom.hs
{-# LANGUAGE GeneralizedNewtypeDeriving #-}

newtype Value a = Val Int deriving (Show, Eq, Ord, Num)

data ValYen
data ValUSD

type Yen = Value ValYen
type USD = Value ValUSD
```

このように、わずかな行数、かつ、シンプルな記述により、目的とする機能を実現できました。

以上、Haskell/GHCの基本的な型システムの機能（`newtype`, `data`, `type`, など）を使うだけで、数のように振る舞い、かつ、互いを区別できる「混ぜられない数」を手軽に実現できました。便利ですね！

では、Happy Haskelling!


4. 補足
=======

以下は、いくつかの補足情報です。長いので、読み飛ばしてもらっても構いません :smiley: 

### 4.1 関連仕様書

以下に、関連するいろいろな情報があります（英語版です）。

* Haskell 2010 Language Report （Haskell言語仕様）:
  * [newtype宣言](https://www.haskell.org/onlinereport/haskell2010/haskellch4.html#x10-740004.2.3)
  * [data宣言](https://www.haskell.org/onlinereport/haskell2010/haskellch4.html#x10-690004.2.1)
  * [type宣言](https://www.haskell.org/onlinereport/haskell2010/haskellch4.html#x10-730004.2.2)
  * [deriving機能](https://www.haskell.org/onlinereport/haskell2010/haskellch11.html)
  * [Eqなどの型クラス定義](https://www.haskell.org/onlinereport/haskell2010/haskellch6.html#x13-1270006.3)
* GHC User's Guide （GHCユーザーズガイド）:
  * [GeneralizedNewtypeDeriving言語拡張](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/glasgow_exts.html#generalised-derived-instances-for-newtypes)
* 各々の型クラスの実装説明 （ライブラリのドキュメント）:
  * [Eq](http://hackage.haskell.org/package/base-4.11.1.0/docs/Prelude.html#t:Eq), 
    [Ord](http://hackage.haskell.org/package/base-4.11.1.0/docs/Prelude.html#t:Ord),
    [Num](http://hackage.haskell.org/package/base-4.11.1.0/docs/Prelude.html#t:Num),
    [Integral](http://hackage.haskell.org/package/base-4.11.1.0/docs/Prelude.html#t:Integral)
* GHCにおけるderiving機能の実装コード （GitHubのGHCリポジトリ）:
  * [Eq, Ord, Show, ...](https://github.com/ghc/ghc/blob/master/compiler/typecheck/TcGenDeriv.hs)
  * [GeneralizedNewtypeDeriving](https://github.com/ghc/ghc/blob/master/compiler/typecheck/TcDeriv.hs)


### 4.2 作成した型の使用

作成した型の使用例についての補足です。

次のように、関数の型シグネチャ（型宣言）の部分に、型変数`a`の表現を残した`Value a`型を使うことにより、`Value a`型に共通の関数を定義できます。
次の`add`関数では、「２つの引数と１つの出力が、全て同じ型であること」を、型変数`a`を共通にすることにより表現しています。
そのため、`Value ValYen`型と`Value ValUSD`型を混ぜて使うことを、コンパイルエラーとして検出できます。

```Haskell:4.2.using.hs
add :: Value a -> Value a -> Value a
add x1 x2 = x1 + x2
```

一方で、次のようにして、対象とする型を限定することもできます。ここでは、`Value a`型の型変数`a`を、`ValYen`にすることで型を具体的にしています。

```Haskell:4.2.using.hs
toYen :: Int -> Value ValYen
toYen x = Val x
```


### 4.3 除算の追加

除算の追加についての補足です。

これまでに紹介した`Num`クラスには、加減乗算（`+`, `-`, `*`）のための演算子が含まれていますが、除算（`div`）の機能は含まれていません。
自作の型において除算（`div`）を使用できるようにするには、以下のように、`Enum`, `Real`, `Integral` をもderivingする必要があります。[^appendix43]

```Haskell:4.3.div.hs
newtype Value a = Val Int deriving (Show, Eq, Ord, Num, Enum, Real, Integral)
```

以下は、使用例です。`div`関数を使用できるようになっています。

```
ghci> x = 100 :: Yen

ghci> x `div` 2
Val 50
```


### 4.4 小数を扱う場合

小数の扱いについての補足です。

これまでの例では、`newtype`で包む対象の数値型として、整数型の`Int`を用いる例を示しました。しかしながら、整数のみではなく、小数点以下の数をも扱いたい場合があると思います。

#### 例4.4.1 : Double型の使用
そのような場合には次のように、整数型の`Int`ではなく、浮動小数点型の`Double`を使う方法があります。
なお、包む対象の型として`Double`型を選択する際に、除算（`/`）をも使えるようにしたい場合には、`deriving`節に`Fractional`を追加します。

```Haskell:4.4.1.Double.hs
newtype Value a = Val Double deriving (Show, Eq, Ord, Num, Fractional)
```

以下は、使用例です。

```
ghci> x = 100 :: Yen

ghci> x / 3
Val 33.333333333333336
```

#### 例4.4.2 : Rational型の使用
上記の浮動小数点の`Double`型は、速度とメモリ効率が良い型ですが、小数点以下の桁を正確には表現できません。
そのような場合には次のように、有理数の`Rational`型を使う方法があります。
`Rational`型にて、除算（`/`）を使いたい場合にも`Double`型と同様に、`deriving`節に`Fractional`を追加します。

```Haskell:4.4.2.Rational.hs
newtype Value a = Val Rational deriving (Show, Eq, Ord, Num, Fractional)
```

以下は、使用例です。

```
ghci> x = 100 :: Yen

ghci> x / 3
Val (100 % 3)
```


### 4.5 newtypeとphantomの組み合わせ、以外による方法

混ぜられない数のグループを作るための、その他の方法についての補足です。

３章では、`newtype`宣言とphantom型の組み合わせにより、互いに区別できる数のグループを作る方法を紹介しました。しかし、互いに区別できる数のグループを作る方法は他にもあります。

#### 例4.5.1 : 各型ごとのnewtype宣言による方法
他の方法の１つめの例として、phantom型を使わない方法があります。
以下のように、各々の型ごとに、`newtype`宣言を個別に用意します。

```Haskell:4.5.1.alt_newtype.hs
{-# LANGUAGE GeneralizedNewtypeDeriving #-}

newtype Yen = ValYen Int deriving (Show, Eq, Ord, Num)
newtype USD = ValUSD Int deriving (Show, Eq, Ord, Num)
```

但し、上記の方法では、３章のように`Value a`型を用いて共通の関数を作る方法は使えません。
しかし、以下のように型クラスの機能を用いることにより、両方の型における共通の関数を実現できます。

```Haskell:4.5.1.alt_newtype.hs
class Num a => Value a where
    add :: a -> a -> a
    add x1 x2 = x1 + x2

instance Value Yen
instance Value USD
```


#### 例4.5.2 : data宣言による方法
他の方法の２つめの例として、`newtype`宣言ではなく、`data`宣言を使う方法があります。
以下のように、`data`宣言の値コンストラクタにより、各々の値のグループを区別します。

```Haskell:4.5.2.alt_data.hs
data Value = Yen Int
           | USD Int
           deriving (Show, Eq, Ord)
```

この方法では、値コンストラクタである`Yen`や`USD`を用いることにより、グループに応じた動作を実行時に変更できます。

しかし、両者とも型が共通の`Value`型であるため、型の世界で数のグループを互いに区別することはできません。すなわち、数のグループの区別は、コンパイル時ではなく実行時に行うことになります。

また、`newtype`宣言ではなく`data`宣言を使う場合には、基本的な型クラス以外をderiving機能により自動導出することはできません。つまり、`Num`クラスをderivingできないため、加減乗除の演算などは、自分で実装する必要があります。


### 4.6 包まれた数値を安全に取り出す

包まれた数値の出し入れについての補足です。

３章では、独自に作った数値型により、各々の数値型を混ぜることなく安全に使える体系を実現できました。しかし、独自に作った数値型から、包まれた数値を取り出す場合に、型を取り間違えてしまう危険性は残ります。

例えば、次のように`Value a`型を入力とし、`Int`型を出力とする関数を作る場合です。この場合、`Value Yen`型と`Value USD`型の引数を間違えて使用しても、コンパイルエラーにはなりません。せっかくの型の体系に危険な穴が開いてしまいます。

```Haskell:4.6.0.from.hs
fromValue :: Value a -> Int
fromValue (Val x) = x
```

例えば次のように、各々の数値のグループに対してfromValueを使い間違えても気づきにくいのです。

```
ghci> y = 100 :: Yen
ghci> z = 1 :: USD

ghci> yen1 = fromValue y
ghci> yen2 = fromValue z      -- mistake
```

これへの対策は幾つかあります。

#### 例4.6.1 : 各型ごとのfromXXX関数
１つめは、抽象的な`Value a`型でなく、型変数`a`を具体化した`Value ValYen`型などを使う方法です。これにより、型を誤って使うことを防ぎます。
ただし、この方法では、数のグループごとに関数を用意（`fromYen`, `fromUSD`, ...）する必要があります。

```Haskell:4.6.1.from.hs
fromYen :: Value ValYen -> Int
fromYen (Val x) = x
```

以下は、使用例です。

```
ghci> y = 100 :: Yen
ghci> z = 1 :: USD

ghci> fromYen y
100
ghci> fromYen z
<interactive>:10:9: error:
```


#### 例4.6.2 : 型を、追加の引数により指定するfromValue関数
２つめは、関数の引数を増やして、関数の使用時に型変数`a`を具体的にする方法です。
次の`fromValue`関数は、１つめの引数の型変数`a`と、２つめの引数の型変数`a`が共通です。

```Haskell:4.6.2.from.hs
data ValYen = ValYen
data ValUSD = ValUSD

fromValue :: a -> Value a -> Int
fromValue _ (Val x) = x
```

次のように使います。`fromValue`の１つめの引数において、型変数`a`に応じた値を指定することで、型を誤って使うことを防ぎます。
以下の例では、変数`y`が、`Val ValYen`型でない場合は、コンパイルエラーとして検出できます。

```
ghci> y = 100 :: Yen
ghci> fromValue ValYen y
100

ghci> fromValue ValUSD y
<interactive>:17:18: error:
```


### 4.7 実行時に型を区別したい場合

長くなりましたが、ここで最後です。
実行時に型を区別する方法ついての簡単な補足です。

本記事の方法では、数のグループが混ざってしまう誤りを、コンパイル時に静的に検出できます。一方で、実行時に型を区別したい場合もあります。つまり例えば、実行時に、数のグループに応じて処理を変えたい場合です。

phantom型を使った３章の方法では、値コンストラクタが共通です（共通の`Val`）。そのため、例4.5.2における`data`宣言を使う方法のように、値コンストラクタを用いて、型に応じて処理を切り替えることはできません。

しかし、GHC拡張機能（[DeriveDataTypeable](https://downloads.haskell.org/%7Eghc/latest/docs/html/users_guide/glasgow_exts.html#extension-DeriveDataTypeable)）とライブラリ[Data.Typeable](http://hackage.haskell.org/package/base-4.11.1.0/docs/Data-Typeable.html)の[typeOf](http://hackage.haskell.org/package/base-4.11.1.0/docs/Data-Typeable.html#v:typeOf) 関数を使うことにより、実行時に型の違いを識別して、型に応じて処理を切り替えることができます。
ここでは詳細は省略しますが、以下がコード例です。

```Haskell:4.7.equalType.hs
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE DeriveDataTypeable #-}                               -- extension

import Data.Typeable                                              -- import

newtype Value a = Val Int deriving (Show, Eq, Ord, Num, Typeable) -- Typeable

data ValYen
data ValUSD

-- function
isYen :: Typeable a => Value a -> Bool                             -- Typeable constraint
isYen x = typeOf x == typeOf (1 :: Value ValYen)                   -- `typeOf`
```

`Data.Typeable`モジュールからimportした`typeOf`関数により、型の一致を判定して、TrueかFalseを返すことができます。
`typeOf`関数を使用するためには、以下の対応が必要です。

  * `DeriveDataTypeable`拡張を有効にする
  * `Data.Typeable`モジュールをimportする
  * 対象とする型の宣言の`deriving`節に、`Typeable`を追加する
  * 使用する関数の型宣言にて、`Typeable x =>`の型クラス制約を記述する


以下は、使用例です。

```
ghci> y = 100 :: Yen
ghci> z = 1 :: USD
ghci> isYen y
True
ghci> isYen z
False
```

実行時に、型に応じて動作を変えられました。

以上です。
本記事ではHaskell/GHCにおける基本的な型の機能により、シンプルに便利なことを実現できることを紹介しました。

では改めて、Happy Haskelling!！

[^newtype1]:  ここでは詳細を省略しますが、`newtype`宣言は、`data`宣言の特別なバージョンのようなものです。`data`宣言とは異なり、右辺には「１つの値コンストラクタと、１つの型」の組み合わせのみを記述できます。また、コンパイルによるコード生成では、「１つの型」側のみが残されるため、実行速度とメモリ使用の効率が良い特徴もあります。

[^newtype2]: `deriving`節により、それぞれの型クラスの関数を導入できます。例えば、`Eq`クラスをderivingすることにより、`Eq`クラスにて定義されている`==`演算子を使用できるようになります。

[^newtype3a]: ghciコマンド内でGHCの言語拡張を有効にするには、`:set -X`に続けて言語拡張名を入力します。また、GHCの言語拡張をプログラムファイル中に記述するには、`{-# LANGUAGE GeneralizedNewtypeDeriving #-}`のように記述します。

[^newtype3b]: Haskellの言語仕様では、`deriving`節で自動導出できる型クラスは、Eq, Ord, Enum, Bounded, Read, Showのみです。GHCの言語拡張`GeneralizedNewtypeDeriving`により、その他の型クラスの自動導出が、`newtype`宣言において可能になります。新たに自動導出できる型クラスは、包む対象の型が属している型クラスです。

[^newtype3c]: `Num`クラスでは、`+`, `-`, `*`などの演算子や、`abs`, `fromInteger`などの関数が定義されています。

[^newtype3d]: `x = 1 :: Value`における `:: Value`の部分は、「型注釈」です。型注釈の機能により、式の特定の部分に、明示的に型を指定することができます。ここでは、式`1`の型が`Value`であることを指定しています。

[^appendix43]: Int型を包む独自の数値型に、Int型が属している型クラスを全て自動導出させたい場合には、さらに`Bounded`クラスをderivingします。注目対象の型がどの型クラスに属しているかを調べるには、ghciコマンドで`:info Int`のように実行します。