语句< - 不为Maybe编译

时间:2014-07-04 03:53:51

标签: haskell

import Network.HTTP.Conduit
import qualified Data.HashMap.Lazy as LHashMap
import Network.HTTP.Types

getJSONObject :: String -> IO Object
--.............

main = do
  jsonObject <- getJSONObject "example.com"
  String a <- LHashMap.lookup "some_key" jsonObject -- doesn't compile
  --.....................................

错误是:

Couldn't match type `Maybe' with `IO'
    Expected type: IO Value
      Actual type: Maybe Value

确实,LHashMap.lookup会返回Maybe,而不是IO。但<- Monads不应该使用Maybe吗? 我如何使它工作?

更新: 根据上面的错误,由于同样的事情,下面的代码不起作用:

let toPrint = do 
                Object jsonObject <- decode $ responseBody res :: Maybe Value
                Object jsonObject2 <- LHashMap.lookup "key1" jsonObject
                Object jsonObject3 <- LHashMap.lookup "key2" jsonObject2
                Array d <- LHashMap.lookup "key3" jsonObject3
                String val <- return $ d ! 1
                return val
  case toPrint of
    Just a -> IO.putStrLn a
    _ -> error "Unexpected JSON"

但确实有效。

2 个答案:

答案 0 :(得分:6)

所有附加值中的monadic值都必须来自同一个Monad。如果你贬低这个记号,很容易看到这个:

main = getJSONObject "example.com" >>= (\jsonObject ->
       LHashMap.lookup "some_key" jsonObject >>= (\String a -> ... ))

查看>>=

的类型
>>= :: Monad m => m a -> (a -> m b) -> m b

请注意,尽管参数m使>>=具有多态性,但对于两个参数和返回值,它都是相同的m

特别是,这意味着类型检查器要求getJSONObject "example.com"返回LHashMap.lookup "some_key" jsonObject >>= (\String a -> ...)所在的同一个monad中的值,这要求LHashMap.lookup "some_key" jsonObject位于同一个monad中。因此你的错误。

您需要弄清楚如何处理失败:

  1. 您可以使用let语句而不是绑定(不推荐)将其设置为模式匹配例外:

    % cat Temp.hs
    module Main where
    
    main = do
      let Just x = Nothing
      putStrLn $ "Hello " ++ x
    
    % runhaskell Temp.hs
    Temp.hs: Temp.hs:4:7-22: Irrefutable pattern failed for pattern Data.Maybe.Just x
    %
    
  2. 你可以把它变成IO monad的失败,这会使它变成一个稍微不同的例外(也不推荐)n

    % cat Temp.hs
    module Main where
    
    main = do
      Just x <- return Nothing
      putStrLn $ "Hello " ++ x
    % runhaskell Temp.hs
    Temp.hs: user error (Pattern match failure in do expression at Temp.hs:4:3-8)
    %
    
  3. 您可以使用case语句(推荐):

    % cat Temp.hs
    module Main where
    
    main = do
      case Nothing of
        Nothing -> return ()
        Just x  -> putStrLn $ "Hello " ++ x
    % runhaskell Temp.hs
    %
    

答案 1 :(得分:5)

do区块中,你使用的monad意味着是同质的,因为它不需要

(>>=) :: Monad m => m a -> (a -> m b) -> m b

由于m在整个绑定过程中是一致的,因此我们在整个块中也必须与它保持一致。

这里正确的解决方案是以纯粹的方式处理maybe,而不是单独处理它#34;。一个简单的解决方案可能就是使用案例表达式

 case LHashMap.lookup "some_key" jsonObject of
    Just res -> some IO here
    Nothing  -> handle failure here

或者只是将其粉碎成带有

的表达式
 maybe :: b -> (a -> b) -> Maybe a -> b