Haskell Quiz No.10

難易度: λ

以下の実行結果はどうなるでしょう!

答えは次回

はじめに

前回の問題と答えは以下の通りです。

問題

難易度: λλ

以下の2つのコードのうち、1つめはコンパイルできますが、2つめはコンパイルできません。

なぜでしょう!

エラーメッセージ

error:
    • No instance for (Num ()) arising from the literal ‘1’
    • In the expression: 1
      In the second argument of ‘mapM_’, namely ‘[1 .. 10]’
      In a stmt of a 'do' block: mapM_ leftover [1 .. 10]

    mapM_ leftover [1..10]

解説

先に2つ目の例がエラーとなってしまう理由を確認します。

まずは関数の型を確認しておきましょう。

次にモナドの型クラスも一応確認しておきます。

さらに型を確認していきます。

さて、ここまで確認するとなぜ2つ目の結果がエラーとなることがわかります。

ConduitT のパラメータはそれぞれ以下のような具体的な型になります。

  • i = ()
  • o = Void
  • m = Identity
  • r = [i]

さらに mi にはクラス制約があるため以下のインスタンス定義が要求されます。

  • instance Monad Identity
  • instance Enum ()
  • instance Num ()

ここで Num クラスのインスタンス定義には () が含まれないため、エラーとなってしまいました。

1つ目の例がエラーにならない理由

ではなぜ return () .| が追加されるとエラーにならないのでしょうか?

型を確認してみます。

2つ目の例では runConduitPure に直接適用してしまったため、型クラス制約が必要になりましたが、今回は return () と合成した結果を runConduitPure に適用するため、この問題を回避することができています。

まとめ

  • runConduitPure に適用する時に今回のようなエラーが出てしまう場合は return () .| として合成してから適用すると良い。

以上です。