別にddump-splicesに限ったわけではないですが。
ghc -ddump-splices Model.hs
~/Documents/OsojiPhoto/OsojiPhoto $ ghc -ddump-splices Model.hs
GooglePlusOAuth.hs:42:8:
Ambiguous module name `Data.Aeson.Types':
it was found in multiple packages:
aeson-0.5.0.0 aeson-native-0.3.3.2
こんなときは
ghc -hide-package aeson-native -ddump-splices Model.hs
参考haskell - Specifying package name for module-related commands in ghci - Stack Overflow
そういう不思議な言語です。
httpLbsは2XXなステータスコードじゃないとエラーになるので、それをControl.Exception.Liftedのcatchで拾ってやるのがこつです。
帰ってきたJSONはData.Aesonで処理してあげます。
http://d.hatena.ne.jp/melpon/20111026/1319602571
getAccessToken :: String -> IO (Maybe Text)
getAccessToken code = do
let payload = [("code", C8.pack code), ("client_id", C8.pack key),
("client_secret", C8.pack sec),
("redirect_uri", "http://localhost:3000/auth/page/GooglePlus"),
("grant_type", "authorization_code")]
parsedUrl <- parseUrl accUrl
let req = urlEncodedBody payload $ parsedUrl
errHandler :: ResourceIO m => HttpException
-> ResourceT m (Response LBS.ByteString)
errHandler (StatusCodeException status hdrs) = return $ Response status hdrs LBS.empty
(status, content) <- withManager $ \manager -> do
Response status _ bsrc <- (httpLbs req manager) `L.catch` errHandler
return (status, bsrc)
putStrLn $ "Got status: " ++ (show status)
case status of
(Status 200 _) -> do
let r = AP.eitherResult $ AP.parse json content
case r of
Left msg -> do
putStrLn $ "Json error" ++ msg
return Nothing
Right d -> do
putStrLn "json ok"
let Object obj = d
t = do
String txt <- M.lookup "access_token" obj
return txt
return t
_ -> do
putStrLn "invalid status"
return Nothing
Haskellの難しいところはいろいろなライブラリが依存関係がいっぱいあるということな気がします。
HTTP Postリクエストをしないといけなかったので、Network.HTTP.Conduitを使ってみた。といってもぜんぜんSourceとかSinkとか出てこないけれども。一部抜粋。
getAccessToken :: String -> IO (Maybe Text)
getAccessToken code = do
let payload = [("code", C8.pack code), ("client_id", C8.pack key),
("client_secret", C8.pack sec),
("redirect_uri", "http://localhost:3000/auth/page/GooglePlus"),
("grant_type", "authorization_code")]
parsedUrl <- parseUrl accUrl
let req = urlEncodedBody payload $ parsedUrl
(statusCode, content) <- withManager $ \manager -> do
Response status _ bsrc <- httpLbs req manager
return (status, bsrc)
putStrLn $ "Got status: " ++ (show statusCode)
Ugoita
Got status: Status {statusCode = 200, statusMessage = "OK"}
StringをByteStringに変換するのはData.ByteString.Char8を使うといいぽい。import qualified Data.ByteString.Char8 as C8。仲間にData.ByteString.UTF-8があるということはきっとユニコードはそっちをつかったほうがいいということだろう。
because type variable `s' would escape its scope - suztomoの日記 - haskellがとりあえず解けた
Type declarationをしたら動いた。
login :: forall s m. (Route Auth -> Route m) -> GWidget s m ()
login tm = do
render <- lift getUrlRender
let oaUrl = render $ tm $ oauthUrl name
addHtml $
[shamlet| <a href=#{oaUrl}>Login with #{name} |]
参考にしたページ。
Haskell - Haskell-Cafe - Enabling GADTs breaks Rank2Types code compilation - Why?
Rank2 Type
第20回 更新を高速化するためのSTモナド - 本物のプログラマはHaskellを使う:ITpro
7.8.?Other type system extensions
{-# LANGUAGE Rank2Types #-} applyTuple :: (forall a. a -> a) -> (Bool, String) applyTuple f = (f True, f "hidamari") applyTuple2 :: forall a. (a -> a) -> (Bool, String) applyTuple2 f = (f True, f "hidamari")
一つ目はfに(Bool -> Bool)がきてもいいし、(String -> String)がきてもいいということ。二つ目は(f True)の時点でaの型が(Bool -> Bool)に固定され、(f "hidamari")の片付け(unification)に失敗する。