2

读完这篇文章后,我尝试了

{-# LANGUAGE OverloadedStrings, NoMonomorphismRestriction #-}
module Login (
    fbUrl,
    fbEmail
) where

-- package http://hackage.haskell.org/package/fb
import qualified Facebook as FB
import Network.HTTP.Conduit (withManager)

app :: FB.Credentials
app = FB.Credentials "localhost" "249348058430770" "..."

url :: FB.RedirectUrl
url = "http://localhost/fb"

perms :: [FB.Permission]
perms = ["user_about_me", "email"]

--fbUrl :: Monad m => FB.FacebookT FB.Auth m Text
fbUrl :: IO Text
fbUrl = withManager $ \manager -> FB.runFacebookT app manager $ FB.getUserAccessTokenStep1 url perms

--fbEmail :: Monad m => (ByteString, ByteString) -> FB.FacebookT FB.Auth m (Maybe Text)
--fbEmail :: (ByteString, ByteString) -> IO (Maybe Text)
fbEmail c = withManager $ \manager -> FB.runFacebookT app manager $ do
    t <- FB.getUserAccessTokenStep2 url [c]
    u <- FB.getUser "me" [] (Just t)
    return $ FB.userEmail u

module Main (
  main
) where

import Login
import qualified Data.ByteString.Char8 as C
import Control.Exception

main :: IO ()
main = do

    let a = ("code","test")
    e <- fbEmail $ (\(x,y) -> (C.pack x, C.pack y)) a

    case e of
        Nothing -> print "doh!"
        Just e -> print e

我得到haskell-facebook: FacebookException {fbeType = "invalid_code", fbeMessage = "Invalid verification code format."}而不是doh!

随着e <- try (fbEmail $ (\(x,y) -> (C.pack x, C.pack y)) a)我得到

Couldn't match expected type `Either
                                e0 (Maybe Data.Text.Internal.Text)'
            with actual type `Maybe t0'
In the pattern: Nothing
In a case alternative: Nothing -> print "doh!"
In a stmt of a 'do' block:
  case e of {
    Nothing -> print "doh!"
    Just e -> print e }

@丹尼尔菲舍尔

let a = ("code","test")
e <- try (fbEmail $ (\(x,y) -> (C.pack x, C.pack y)) a)

case e of
    Left x -> print "doh!"
    Right e -> print "ok"

Ambiguous type variable `e0' in the constraint:
  (Exception e0) arising from a use of `try'
Probable fix: add a type signature that fixes these type variable(s)
In a stmt of a 'do' block:
  e <- try (fbEmail $ (\ (x, y) -> (C.pack x, C.pack y)) a)
In the expression:
  do { let a = ...;
       e <- try (fbEmail $ (\ (x, y) -> (C.pack x, C.pack y)) a);
       case e of {
         Left x -> print "doh!"
         Right e -> print "ok" } }
In an equation for `main':
    main
      = do { let a = ...;
             e <- try (fbEmail $ (\ (x, y) -> (C.pack x, C.pack y)) a);
             case e of {
               Left x -> print "doh!"
               Right e -> print "ok" } }

当我添加类型签名时fbEmail :: Monad m => (ByteString, ByteString) -> FB.FacebookT FB.Auth m (Maybe Text),我得到

Could not deduce (monad-control-0.3.1.3:Control.Monad.Trans.Control.MonadBaseControl
                    IO m,
                  resourcet-0.3.2.2:Control.Monad.Trans.Resource.MonadUnsafeIO m,
                  Control.Monad.IO.Class.MonadIO m,
                  resourcet-0.3.2.2:Control.Monad.Trans.Resource.MonadThrow
                    (FB.FacebookT FB.Auth m))
  arising from a use of `withManager'
from the context (Monad m)
  bound by the type signature for
             fbEmail :: Monad m =>
                        (ByteString, ByteString) -> FB.FacebookT FB.Auth m (Maybe Text)
  at src/Login.hs:(25,1)-(28,27)
Possible fix:
  add (monad-control-0.3.1.3:Control.Monad.Trans.Control.MonadBaseControl
         IO m,
       resourcet-0.3.2.2:Control.Monad.Trans.Resource.MonadUnsafeIO m,
       Control.Monad.IO.Class.MonadIO m,
       resourcet-0.3.2.2:Control.Monad.Trans.Resource.MonadThrow
         (FB.FacebookT FB.Auth m)) to the context of
    the type signature for
      fbEmail :: Monad m =>
                 (ByteString, ByteString) -> FB.FacebookT FB.Auth m (Maybe Text)
  or add instance declarations for
     (monad-control-0.3.1.3:Control.Monad.Trans.Control.MonadBaseControl
        IO m,
      resourcet-0.3.2.2:Control.Monad.Trans.Resource.MonadThrow
        (FB.FacebookT FB.Auth m))
In the expression: withManager
In the expression:
  withManager
  $ \ manager
      -> FB.runFacebookT app manager
         $ do { t <- FB.getUserAccessTokenStep2 url [...];
                u <- FB.getUser "me" [] (Just t);
                .... }
In an equation for `fbEmail':
    fbEmail c
      = withManager
        $ \ manager
            -> FB.runFacebookT app manager
               $ do { t <- FB.getUserAccessTokenStep2 url ...;
                      .... }

当我添加时,fbEmail :: (ByteString, ByteString) -> IO (Maybe Text)我得到

Ambiguous type variable `e0' in the constraint:
  (Exception e0) arising from a use of `try'
Probable fix: add a type signature that fixes these type variable(s)
In a stmt of a 'do' block:
  e <- try (fbEmail $ (\ (x, y) -> (C.pack x, C.pack y)) a)
In the expression:
  do { couchTest;
       u <- fbUrl;
       print u;
       let a = ...;
       .... }
In an equation for `main':
    main
      = do { couchTest;
             u <- fbUrl;
             print u;
             .... }
4

1 回答 1

3

try在结果之上添加另一层。为了使这个示例简单,我使用 catch-all 来捕获所有异常SomeException

为了更清楚一点,这里是添加了 type signatured 的结果类型:

e :: Maybe Text <- fbEmail $ (\(x,y) -> (C.pack x, C.pack y)) a

与此用法相比,try异常类型等于SomeException

e :: Either SomeException (Maybe Text) <- fbEmail $ (\(x,y) -> (C.pack x, C.pack y)) a

正如 Daniel 在他的评论中提到的那样,使用模式匹配来处理这些更复杂的类型很简单:

{-# LANGUAGE FlexibleContexts, OverloadedStrings #-}
module Main where

import Control.Exception
import qualified Data.ByteString.Char8 as C
import Data.Text
import Network.HTTP.Conduit (withManager)

import qualified Facebook as FB

app :: FB.Credentials
app = FB.Credentials "localhost" "249348058430770" "..."

url :: FB.RedirectUrl
url = "http://localhost/fb"

perms :: [FB.Permission]
perms = ["user_about_me", "email"]

fbUrl :: IO Text
fbUrl = withManager $ \manager -> FB.runFacebookT app manager $ FB.getUserAccessTokenStep1 url perms

fbEmail :: FB.Argument -> IO (Maybe Text)
fbEmail c = withManager $ \manager -> FB.runFacebookT app manager $ do
  t <- FB.getUserAccessTokenStep2 url [c]
  u <- FB.getUser "me" [] (Just t)
  return $ FB.userEmail u

main :: IO ()
main = do
  let a = ("code","test")
  e <- try . fbEmail $ (\(x,y) -> (C.pack x, C.pack y)) a

  case e of
    Left e -> print $ "error: " ++ show (e :: SomeException)
    Right Nothing -> print "doh!"
    Right (Just e) -> print e
于 2012-08-03T23:15:49.130 回答