LoginSignup
4
0

More than 5 years have passed since last update.

PreludeのfailはMonadFailのfailではない(ケアレスミス)

Last updated at Posted at 2017-08-13

困ったこと

 僕はよく失敗表現の型をMonadFailインスタンスにして、failを使って失敗を抽象化するなどをするんだけど、
それに対するテストでfailを使うと、何故かそのインスタンスのfailが呼ばれず、IO例外が送出されることがある。

Test.hs (テスト用のコード) vv

{-# LANGUAGE GeneralizedNewtypeDeriving #-}

module Test
  ( ExceptionCause
  , Result (..)
  ) where

import Control.Monad.Fail (MonadFail(..))

type ExceptionCause = String

newtype Result a = Result
  { unResult :: Either ExceptionCause a
  } deriving (Show, Eq, Functor, Applicative, Monad)

instance MonadFail Result where
  fail = Result . Left

Main.hs (テスト) vv

import Test (Result(..))


-- tasty-discover用の命名
test_it_is_pure :: Bool
test_it_is_pure = pureFail "x(" == negativeContext "x("
  where
    -- Expected behavior
    pureFail :: String -> Result ()
    pureFail = Result . Left

    -- An alias of `Result`'s fail
    negativeContext :: String -> Result ()
    negativeContext = fail -- (!!)


main :: IO ()
main = print test_it_is_pure

 このテストは通らない。
(以下の出力になる)

$ stack runghc Main.hs Test.hs
Main.hs: x(

Control.Monad.Failのfailを明示的にimportする

 これはnegativeContextPreludefailを呼んでしまっていることに起因する。

Prelude.fail            :: Monad     m => String -> m a
Control.Monad.Fail.fail :: MonadFail m => String -> m a

 テストを修正する。

Main.hs

import Control.Monad.Fail (fail)
import Prelude hiding (fail)
import Test (Result(..))


-- tasty-discover用の命名
test_it_is_pure :: Bool
test_it_is_pure = pureFail "x(" == negativeContext "x("
  where
    -- Expected behavior
    pureFail :: String -> Result ()
    pureFail = Result . Left

    -- An alias of `Result`'s fail
    negativeContext :: String -> Result ()
    negativeContext = fail -- (!!)


main :: IO ()
main = print test_it_is_pure

出力

$ stack runghc Main.hs Test.hs
True

要するにMonadFailProposalより前の歴史のせい!

4
0
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
0