Haskell初心者が直面するghciで起こしがちなエラー4選とその対処法


対話環境は便利ですが、Haskellでは強い静的型付け・純粋関数型という言語の性質から、
コンパイラと対話環境とでは少々使い勝手が違います。
ここでは、Haskell初心者が`ghci`を使うときに陥りがちな4つの落とし穴について紹介します。

##  1. 式を定義しようとしたら `parse error on input ｀='`

<b>[原因] ghciはインタプリタなので、与えられた式全体を評価しようとする</b>

```
Prelude> hoge = "foo"

<interactive>:5:6: parse error on input `='
```

<b>[解決方法] `let`構文を利用する</b>

```
Prelude> let hoge = "foo"
Prelude> hoge
"foo"
```



## 2. 式を評価しようとしたら `No instance for (Show Hoge)`

* ghciはIOモナドの中にいて、式を与えるたび`print (式)`を実行している
* 式を表示可能にするためには、型が`Show`クラスのインスタンスである必要がある
(`print`は型`Show a => a -> IO ()`を持つ。)


<b>[原因1] 自分で定義した代数的データ型が`Show`クラスに属していない</b>

```
Prelude>  data Tree a = Branch (Tree a) (Tree a) | Leaf a
Prelude> Leaf "hoge"

<interactive>:5:1:
    No instance for (Show (main::Interactive.Tree [Char]))
      arising from a use of `print'
    Possible fix:
      add an instance declaration for
      (Show (main::Interactive.Tree [Char]))
    In a stmt of an interactive GHCi command: print it
```

<b>[解決方法] `deriving Show`をつけて自動的に`Show`クラスのインスタンスになるようにする</b>

```
Prelude> data Tree a = Branch (Tree a) (Tree a) | Leaf a deriving Show
Prelude> Leaf "hoge"
Leaf "hoge"
```


<b>[原因2] 簡約結果の型が関数</b>

```
Prelude> let addOne = (+1)
Prelude> addOne

<interactive>:15:1:
    No instance for (Show (Integer -> Integer))
      arising from a use of `print'
    Possible fix:
      add an instance declaration for (Show (Integer -> Integer))
    In a stmt of an interactive GHCi command: print it
```

<b>[解決方法] 諦める or 関数適用した結果を表示するようにする</b>


## 3. do式を書こうとして改行したら `Empty 'do' block` (または複数行に渡る式が書けない)


<b>[原因] 一行ずつ実行される対話環境では、インデント記法ではdo式の終端を判断できない</b>

```haskell
-- parseAtom :: Parser LispVal
parseAtom = do
 first <- letter <|> symbol
 rest <- many (letter <|> digit <|> symbol)
 let atom = first:rest
 return $ case atom of 
  "#t" -> Bool True
  "#f" -> Bool False
  _ -> Atom atom

```
このような式をghciで定義しようとして、
一行目を入れて改行したところで、

```
Prelude> let parseAtom = do

<interactive>:12:17: Empty 'do' block
```
となる。

<b>[解決方法1] brace記法を利用して頑張って一行に収める</b>

braceで囲えば、`;`がデリミタとして使える。

```
let parseAtom = do { 
 first <- letter <|> symbol; rest <- many (letter <|> digit <|> symbol); let {atom = first:rest}; return $ case atom of { "#t" -> Bool True; "#f" -> Bool False; _ -> Atom atom } } :: Parser LispVal -- ここまで改行なし
```

このように頑張って一行に収めれば`do`構文を`ghci`で利用できる。
`case`構文もbrace記法で記述できる。
ちなみに、brace記法の場合、`do`構文の中で`let`構文を利用する場合、もう一段`{` ~ `}`で囲ってやらなきゃいけない。
(http://stackoverflow.com/questions/15273158/how-do-i-use-a-let-within-a-do-block-in-ghci)

<b>[解決方法2] ghciの`multiline`コマンドを実行する</b>

* `:`から始まる行はghciのコマンド
* `:{`と`:}`のセットとなった`multiline`コマンドを利用することで、複数行に渡る式を記述できる

```
ghci> :{
ghci| let parseAtom = do
ghci|      first <- letter <|> symbol
ghci|      rest <- many (letter <|> digit <|> symbol)
ghci|      let atom = first:rest
ghci|      return $ case atom of 
ghci|       "#t" -> Bool True
ghci|       "#f" -> Bool False
ghci|       _ -> Atom atom
ghci| :}  :: Parser LispVal
```

この場合、一行目の`parseAtom`の先頭よりも二行目以降が右側にインデントされていないと、
インサイドルールにより構文エラーとなる。どこかからソースをコピペしようとする場合、先頭に`let `を加えただけで実行しようとすると構文エラーになるので、二行目以降の各行を4文字分インデントする必要がある。

## 4. 式を評価しようとしたら `Ambiguous type variable   in the constraint`


<b>[原因] あなたが評価しようとしている式には文脈が足らない</b>

* HaskellのようなHM型の静的型付け言語は式に多相性があり、型推論を行うことで最終的な型が決定される
* ソースコードの一部を抜き出してインタプリタで実行するだけでは、型を推論するのに情報が足らない場合がある

<b>[解決方法] 型注釈を与える</b>

`let hogehoge = fugafuga :: Hoge` `let`構文の末尾に型注釈を書ける

`multiline`コマンドを利用しlet式で長い関数を定義用とする場合は、

```
Prelude> :{
Prelude | let parseString = do
Prelude |                     char '"'
Prelude |                     x <- many (noneOf "\"")
Prelude |                     char '"'
Prelude |                     return $ String x :: Parser LispVal
Prelude | :}
```

こんな感じ。式`x`のみを注釈しているように見えるが、ちゃんとletで定義した式全体の型を注釈している。