11015


以下のHaskellコードはGHCで問題なくコンパイルされます。

[code]

    f :: String -> MaybeT IO String
    f x =
        MaybeT $ do
            s <- getLine
            case s of
             "y" ->
                 pure . pure =<< getLine
             _ ->
                 empty
    
[/code]

実行すると`empty`のケースのときエラーになってしまいます。

[code]

    > runMaybeT $ f "a"
    b
    *** Exception: user error (mzero)
    
[/code]

`empty`のケースの型が間違っているので、そこを修正すれば動作します。

[code]

    f :: String -> MaybeT IO String
    f x =
        MaybeT $ do
            s <- getLine
            case s of
             "y" ->
                 pure . pure =<< getLine
             _ ->
                 pure empty
    
[/code]

期待どおりになります。

[code]

    > runMaybeT $ f "a"
    b
    Nothing
    
[/code]

最初のコードを型エラーとしてコンパイル時にはじいてほしいのですが、どうして型チェックをすりぬけてしまうのでしょうか。  
GHCに与えるオプションの調整が必要でしょうか。`-Wall`は付けています。

環境は以下です。

> uname -v  
>  Darwin Kernel Version 14.3.0: Mon Mar 23 11:59:05 PDT 2015;
> root:xnu-2782.20.48~5/RELEASE_X86_64  
>  ghc -V  
>  The Glorious Glasgow Haskell Compilation System, version 7.10.1

* * *

追記： `import`しているモジュールの定義による影響であるという指摘がありましたので、どれが該当するのか調べました

LibZip-0.11.1パッケージの

[code]

    import Codec.Archive.LibZip
    
[/code]

または ListLike-4.2.0パッケージの

[code]

    import System.Process.ListLike
    
[/code]

のいづれかの行を追加したときにコンパイルエラーにならず、実行時エラーになりました。  
どちらもimportしなければ、期待どおりコンパイルエラーになります。

どちらでも発生するので、このモジュールそのものではなく、内部でimportしている別のモジュールが影響しているのだろうと思いましたが、それがどれなのかまでは僕のスキルでは特定できませんでした。


CC BY-SA 3.0
2015-06-05T09:05:18.783
11009
2015-06-06T03:19:00.487
2015-06-05T17:24:56.257
9731
9731
question
macos haskell
実行時にエラーが出る次のプログラムのコンパイルが通ってしまうのはどうしてでしょうか


提示されたコードに必要な`import`を追加しただけで試すと、GHC-7.10.1ではコンパイルエラーになります。

[code]

    import Control.Applicative
    import Control.Monad.Trans.Maybe
    
    f :: String -> MaybeT IO String
    f x =
        MaybeT $ do
            s <- getLine
            case s of
             "y" ->
                 pure . pure =<< getLine
             _ ->
                 empty
    
[/code]

エラーメッセージは以下の通りです。

[code]

    a.hs:21:14:
        No instance for (Alternative IO) arising from a use of ‘empty’
        In the expression: empty
        In a case alternative: _ -> empty
        In a stmt of a 'do' block:
          case s of {
            "y" -> pure . pure =<< getLine
            _ -> empty }
    
[/code]

提示された実行時のエラーメッセージ（`*** Exception: user error
(mzero)`）から想像すると、他にインポートしているモジュールの中で、以下の様な形のIOに対するAlternativeのインスタンスが宣言されているのではないかと思います。

[code]

    instance MonadPlus IO where
        mzero = fail "mzero"
        mplus = undefined -- 実行時例外をキャッチするような実装（省略）
    
    instance Alternative IO where
        empty = mzero
        (<|>) = mplus
    
[/code]

このようなインスタンス宣言を追加した上で試すと、コンパイルエラーにはなりませんし、実行時には提示されたエラーが発生します。

* * *

追記

インスタンスがどのモジュールで定義されているかは、ghciの`:info`コマンドを使うと確認できます。例えば、`System.Process.ListLike`をインポートした状態で試すと以下の様な出力が得られ、該当のインスタンスは、`Control.Monad.Trans.Error`で定義されていることがわかります。

[code]

    Prelude> :m Control.Applicative Control.Monad System.Process.ListLike
    Prelude Control.Applicative Control.Monad System.Process.ListLike> :info IO
    newtype IO a
      = GHC.Types.IO (GHC.Prim.State# GHC.Prim.RealWorld
                      -> (# GHC.Prim.State# GHC.Prim.RealWorld, a #))
        -- Defined in ‘GHC.Types’
    instance Monad IO -- Defined in ‘GHC.Base’
    instance Functor IO -- Defined in ‘GHC.Base’
    instance Applicative IO -- Defined in ‘GHC.Base’
    instance MonadPlus IO -- Defined in ‘Control.Monad.Trans.Error’
    instance Alternative IO -- Defined in ‘Control.Monad.Trans.Error’
    
[/code]


CC BY-SA 3.0
2015-06-05T14:11:24.213
11015
2015-06-06T03:19:00.487
2015-06-06T03:19:00.487
3066
3066
11009
answer