我在SO上看到了这个问题,并试图复制它:Haskell: Reusing FromJSON instances with lenses, lens-aeson, and nested JSON
但是,当我运行我认为应该是一个完整的例子时,我得到一个错误。
这是我的代码:
import Data.Aeson
import Data.Aeson.Lens
import Control.Lens
import Data.Aeson.Types
data Colour = Yellow | Green | Blue
instance FromJSON Colour where
parseJSON (String s) = return $ case s of
"blue" -> Blue
"green" -> Green
_ -> Yellow
parseJSON _ = mzero
instance ToJSON Colour where
toJSON Yellow = String "yellow"
toJSON Blue = String "blue"
toJSON Green = String "green"
parseColour :: String -> Maybe Colour
parseColour j = j ^? key "info" . key "colour" . _JSON
parseColour "{ \"info\": { \"colour\": \"yellow\" } }"
我明白了:
<interactive>:7:17: error: Variable not in scope: mzero :: Parser Colour
很多搜索都成功地显示了这样使用的mzero变量。我不知道它是从包中导入的东西还是只是一个任意的变量名,而且我在滥用这个功能。无论哪种方式,我都不清楚为什么从问题中复制此代码似乎在此失败。
mzero
是在MonadPlus
中定义的Control.Monad
类型类的一部分。
> import Control.Monad
> :info MonadPlus
class (GHC.Base.Alternative m, Monad m) =>
MonadPlus (m :: * -> *) where
mzero :: m a
mplus :: m a -> m a -> m a
它作为mplus
函数的身份,使mplus mzero x == x
和mplux x mzero == x
。
mzero
在FromJSON
实例中的使用在文档中提到:
在编写实例时,使用empty,mzero或者无法使转换失败,例如如果对象缺少必需的键,或者值的类型错误。
所以在你引用的实例中
instance FromJSON Colour where
parseJSON (String s) = return $ case s of
"blue" -> Blue
"green" -> Green
_ -> Yellow
parseJSON _ = mzero
mzero
表示除了String
之外没有JSON值可以解释为编码Colour
值。