『Haskell 教養としての関数型プログラミング』 5-13 やってみよう でコンパイルエラーを起こしてしまった

ヒントを見落としてしまっただけだったというオチなのだが、まだHaskellに関する知識が十分でない段階でエラーが発生し解決に苦労したので後進の為に書き残しておく。

# 環境

```bash
$ stack ghc -- --version
The Glorious Glasgow Haskell Compilation System, version 8.0.2
```

# 最初の私の解答及び実行結果

### 解答

```haskell:funpaala/exercise/5-13.hs
div3 x
  | x `mod` 3 == 0 = x / 3
  | otherwise = x
```

### 実行結果

```bash
# 学習用環境で対話環境を起動しhsファイルを読み込む
$ cd funpaala
$ stack ghci
*Main Funpaala> :load exercise/5-13.hs

*Main> div3 3
<interactive>:64:1: error:
    • Ambiguous type variable ‘a0’ arising from a use of ‘print’
      prevents the constraint ‘(Show a0)’ from being solved.
      Probable fix: use a type annotation to specify what ‘a0’ should be.
      These potential instances exist:
        instance Show Ordering -- Defined in ‘GHC.Show’
        instance Show Integer -- Defined in ‘GHC.Show’
        instance Show a => Show (Maybe a) -- Defined in ‘GHC.Show’
        ...plus 22 others
        ...plus 12 instances involving out-of-scope types
        (use -fprint-potential-instances to see them all)
    • In a stmt of an interactive GHCi command: print it

*Main> div3 4
<interactive>:65:1: error:
    • Ambiguous type variable ‘a0’ arising from a use of ‘print’
      prevents the constraint ‘(Show a0)’ from being solved.
      Probable fix: use a type annotation to specify what ‘a0’ should be.
      These potential instances exist:
        instance Show Ordering -- Defined in ‘GHC.Show’
        instance Show Integer -- Defined in ‘GHC.Show’
        instance Show a => Show (Maybe a) -- Defined in ‘GHC.Show’
        ...plus 22 others
        ...plus 12 instances involving out-of-scope types
        (use -fprint-potential-instances to see them all)
    • In a stmt of an interactive GHCi command: print it
```

エラーメッセージでググってみても型が曖昧になってしまっている部分があるらしいこと以外何もわからなかったので、演習自体をひとまず飛ばし、先に進むことにした。

なお、私はこのエラーが`div3 3`などの実行時に発生しているものだと思っていたが、実際には`div3 3`などを実行する前にコンパイルする段階でエラーが発生していたことがコメントで頂いた指摘によりわかった(ありがとうございます)。

# 型を定義してみた結果、原因が判明

II部を最後まで読んで、型宣言をおぼえたので、型を定義してみる。よく見るとエラーメッセージにも`use a type annotation to specify what ‘a0’ should be.`とある。

### 解答

```haskell:funpaala/exercise/5-13.hs
div3 :: Int -> Int
div3 x
  | x `mod` 3 == 0 = x / 3
  | otherwise = x
```

### 実行結果

```bash
# 学習用環境で対話環境を起動しhsファイルを読み込む
$ cd funpaala
$ stack ghci
*Main Funpaala> :load exercise/5-13.hs

[1 of 1] Compiling Main             ( exercise/5-13.hs, interpreted )

exercise/5-13.hs:3:22: error:
    • No instance for (Fractional Int) arising from a use of ‘/’
    • In the expression: x / 3
      In an equation for ‘div3’:
          div3 x
            | x `mod` 3 == 0 = x / 3
            | otherwise = x
Failed, modules loaded: none.
```

`/`演算子がInt型の値を返さないことが問題になっているらしい。そういえば/演算子を使って返ってくる値は少なくとも整数値ではなかった気がする。

```bash
*Main> 1 / 1
1.0
```

# 最終的な解答と実行結果

### 解答

```haskell:funpaala/exercise/5-13.hs
div3 x
  | x `mod` 3 == 0 = x `div` 3
  | otherwise = x
```

この段階では著者は型定義の使用を想定していないはずなので、型定義なしでコンパイルが通り正しく動作することを確認する。

### 実行結果
```bash
# 学習用環境で対話環境を起動しhsファイルを読み込む
$ cd funpaala
$ stack ghci
*Main Funpaala> :load exercise/5-13.hs

# コンパイル成功
[1 of 1] Compiling Main             ( exercise/5-13.hs, interpreted )
Ok, modules loaded: Main.

# 実行結果OK
*Main> div3 3
1
*Main> div3 4
3
```

# ヒントはよく読もう

>
関数mod, divと演算子(==)を使います

ちゃんと書かれていた...。他の言語だと除算は`/`演算子で行うことが多いので、ついスルーしてしまった。

# 修正履歴
2021/08/10: コメントで実行時エラーではなくコンパイルエラーであるという指摘を頂いた為全体的に修正。