如何使这样的功能`shouldBeRight :: a b-> IO b`?

时间:2019-02-08 20:47:30

标签: haskell

为了获得“ Right”值或“ Just”值,我正在尝试实现以下两个功能。但是不能编译,为什么呢?

shouldBeRight :: (Show a) => Either a b -> IO b
shouldBeRight (Left a) =
  throwIO $ concat ["should be Right value but wasn't, because:", show a]
shouldBeRight (Right b) = return b

shouldBeJust :: Maybe a -> IO a
shouldBeJust Nothing = throwIO "should be Just value but was Nothing"
shouldBeJust (Just a) = return a

以下是错误:

    • Ambiguous type variable ‘e0’ arising from a use of ‘throwIO’
      prevents the constraint ‘(GHC.Exception.Exception
                                  e0)’ from being solved.
      Probable fix: use a type annotation to specify what ‘e0’ should be.
      These potential instances exist:
        30 instances involving out-of-scope types
        (use -fprint-potential-instances to see them all)
    • In the expression: throwIO "should be Just value but is nothing"
      In an equation for ‘shouldBeJust’:
          shouldBeJust Nothing
            = throwIO "should be Just value but is nothing"
   |
23 | shouldBeJust Nothing = throwIO "should be Just value but is nothing"
   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...

    • Ambiguous type variable ‘e0’ arising from the literal ‘"should be Just value but is nothing"’
      prevents the constraint ‘(Data.String.IsString
                                  e0)’ from being solved.
      Probable fix: use a type annotation to specify what ‘e0’ should be.
      These potential instances exist:
        instance a ~ Char => Data.String.IsString [a]
          -- Defined in ‘Data.String’
        ...plus 13 instances involving out-of-scope types
        (use -fprint-potential-instances to see them all)
    • In the first argument of ‘throwIO’, namely
        ‘"should be Just value but is nothing"’
      In the expression: throwIO "should be Just value but is nothing"
      In an equation for ‘shouldBeJust’:
          shouldBeJust Nothing
            = throwIO "should be Just value but is nothing"
   |
23 | shouldBeJust Nothing = throwIO "should be Just value but is nothing"
   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

1 个答案:

答案 0 :(得分:8)

编译器不知道您要尝试throwIO的异常类型。

从错误消息来看,您可能已启用-XOverloadedStrings,这意味着字符串文字,例如"abcd",没有确定的类型,但是可以采用任何期望的类型,只要有一个IsString实例即可。最常用的字符串类型是StringText,但是还有其他类型,您也可以自己创建。

另一方面,函数throwIO :: Exception e => e -> IO a也没有指定任何特定类型:只要有e,它就可以使用任何类型Exception。实例。

因此,编译器类型不知道选择哪种类型。没有任何选择的依据。

应该解决的“正常”方法是创建自己的异常类型并为其提供一个Exception实例,如下所示:

data MyConversionException = NotJust | NotRight String deriving (Typeable, Show)

instance Exception MyConversionException

然后将其抛出:

shouldBeRight (Left a) = throwIO $ NotRight (show a)

...

shouldBeJust Nothing = throwIO NotJust

如果您确实希望异常在发生时显示该特定文本,则可以始终为其提供自定义Show实例:

instance Show MyConversionException where
    show NotJust = "should be Just value but was Nothing"
    show (NotRight leftValue) = "should be Right value but wasn't, because:" ++ leftValue

或者,如果您只想要快速解决问题的方法,可以使用error函数,该函数会生成运行时异常,类似于throwIO,但其类型是纯净的,因此也可以在IO外部使用:

shouldBeJust Nothing = error "should be Just value but was Nothing"