2017-03-10 14 views
0

머리말 : 저는 아직도 하스켈의 멍청한 놈입니다. 분명히 뭔가 빠져 있다면 용서해주세요. 비표준 데이터 유형 (전자 메일 주소)이있는 필드가있는 레코드 데이터 유형에 대해 aJSON ToJSON 및 FromJSON 인스턴스를 작성하려고합니다.Aeson 레코드의 사용자 정의 데이터 유형 사용하기

/home/gigavinyl/Projects/ordermage/src/components/User.hs:59:26: error: 
    • Couldn't match type ‘Maybe’ 
        with ‘aeson-0.11.2.1:Data.Aeson.Types.Internal.Parser’ 
     Expected type: aeson-0.11.2.1:Data.Aeson.Types.Internal.Parser 
         EmailAddress 
     Actual type: Maybe EmailAddress 
    • In a stmt of a 'do' block: s <- emailAddress (pack (o .: "age")) 
     In a stmt of a 'do' block: 
     userEmail <- do { s <- emailAddress (pack (o .: "age")); 
          case s of { 
          Nothing -> fail "Invalid email address" 
          Just x -> return x } } 
     In the expression: 
     do { userId <- o .: "userId"; 
      userName <- o .: "userName"; 
      userEmail <- do { s <- emailAddress (pack (o .: "age")); 
           case s of { 
           Nothing -> ... 
           Just x -> ... } }; 
      userLevel <- o .: "userLevel"; 
      .... } 

/home/gigavinyl/Projects/ordermage/src/components/User.hs:59:46: error: 
    • Couldn't match type ‘aeson-0.11.2.1:Data.Aeson.Types.Internal.Parser 
          a0’ 
        with ‘[Char]’ 
     Expected type: String 
     Actual type: aeson-0.11.2.1:Data.Aeson.Types.Internal.Parser a0 
    • In the first argument of ‘pack’, namely ‘(o .: "age")’ 
     In the first argument of ‘emailAddress’, namely 
     ‘(pack (o .: "age"))’ 
     In a stmt of a 'do' block: s <- emailAddress (pack (o .: "age")) 

/home/gigavinyl/Projects/ordermage/src/components/User.hs:61:23: error: 
    • Couldn't match expected type ‘EmailAddress’ 
        with actual type ‘Maybe t0’ 
    • In the pattern: Nothing 
     In a case alternative: Nothing -> fail "Invalid email address" 
     In a stmt of a 'do' block: 
     case s of { 
      Nothing -> fail "Invalid email address" 
      Just x -> return x } 

/home/gigavinyl/Projects/ordermage/src/components/User.hs:62:23: error: 
    • Couldn't match expected type ‘EmailAddress’ 
        with actual type ‘Maybe EmailAddress’ 
    • In the pattern: Just x 
     In a case alternative: Just x -> return x 
     In a stmt of a 'do' block: 
     case s of { 
      Nothing -> fail "Invalid email address" 
      Just x -> return x } 

어떻게 제대로 이러한 인스턴스를 작성하려면 어떻게해야합니까 :

{-# LANGUAGE DataKinds #-} 
{-# LANGUAGE DeriveGeneriC#-} 
{-# LANGUAGE LambdaCase #-} 
{-# LANGUAGE OverloadedStrings #-} 
{-# LANGUAGE RecordWildCards #-} 
{-# LANGUAGE TypeOperators #-} 

module User where 

import Control.Monad.Trans.Except 
import Data.Aeson 
import Data.ByteString.Char8 (pack) 
import Data.Maybe 
import GHC.Generics 
import Servant 
import Text.Email.Validate 

type UserApi = 
    "user" :> Get '[JSON] [User] :<|> 
    "user" :> Capture "userId" Integer :> Get '[JSON] User 

userServer :: Server UserApi 
userServer = 
    getUsers :<|> 
    getUserById 

getUsers :: Handler [User] 
getUsers = return [exampleUser] 

getUserById :: Integer -> Handler User 
getUserById = \ case 
    0 -> return exampleUser 
    _ -> throwE err404 

exampleUser :: User 
exampleUser = User 0 "L. Smith" (fromJust (emailAddress "[email protected]")) Base 

-- * user info 
data UserLevel = Base | Admin 
    deriving (Eq, Show, Generic) 

data User 
    = User { 
    userId :: Integer, 
    userName :: String, 
    userEmail :: EmailAddress, 
    userLevel :: UserLevel 
    } 
    deriving (Eq, Show, Generic) 

instance ToJSON User where 
    toJSON (User userId userName userEmail userLevel) = 
     object ["userId" .= userId, "userName" .= userName, "userEmail" .= show userEmail, "userLevel" .= show userLevel] 

instance FromJSON User where 
    parseJSON = withObject "user" $ \o -> do 
    userId <- o .: "userId" 
    userName <- o .: "userName" 
    userEmail <- do s <- emailAddress (pack (o .: "age")) 
        case s of 
         Nothing -> fail "Invalid email address" 
         Just x -> return x 
    userLevel <- o .: "userLevel" 
    return User{..} 

GHC는 이러한 오류를 출력?

답변

0

먼저 Generic에서 파생 될 때 instance FromJSON UserLevel을 추가하십시오. EmailAddress 유형을 구문 분석을 위해 나는 당신이이 수입을 추가해야합니다 (유형 서명을 제거하고 ++에 의해 <> 교체)이 대한

here에서 FromJSON 인스턴스 구현을 사용뿐만 아니라

import Data.Aeson.Types (Parser) 
import Data.Text.Encoding (encodeUtf8) 

그리고 전체 코드 관련 JSON은

를 구문 분석
-- * user info 
data UserLevel = Base | Admin 
    deriving (Eq, Show, Generic) 
instance FromJSON UserLevel 

data User 
    = User { 
    userId :: Integer, 
    userName :: String, 
    userEmail :: EmailAddress, 
    userLevel :: UserLevel 
    } 
    deriving (Eq, Show, Generic) 

instance ToJSON User where 
    toJSON (User userId userName userEmail userLevel) = 
     object ["userId" .= userId, "userName" .= userName, "userEmail" .= show userEmail, "userLevel" .= show userLevel] 


instance FromJSON EmailAddress where 
    parseJSON = withText "EmailAddress" $ \t -> 
        case validate $ encodeUtf8 t of 
         Left err -> fail $ "Failed to parse email address: $ 
         Right email -> return email 

instance FromJSON User where 
    parseJSON = withObject "user" $ \o -> do 
    userId <- o .: "userId" 
    userName <- o .: "userName" 
    userEmail <- o .: "userEmail" 
    userLevel <- o .: "userLevel" 
    return User{..} 

{-- My prefer syntax for json parsing 
instance FromJSON User where 
    parseJSON (Object o) = 
    User <$> 
    o .: "userId" <*> 
    o .: "userName" <*> 
    o .: "userEmail" <*> 
    o .: "userLevel" 
--}