具有postgresql-simple的嵌套类型的FromRow实例

时间:2015-04-28 22:00:15

标签: postgresql haskell

我使用以下类型来表示用户:

data CredentialsRep uType pType = Credentials { username :: uType
                                              , password :: pType } deriving (Show)

data NameRep fType lType = Name { first :: fType
                                , last  :: lType } deriving (Show)

data UserRep cType nType = User { credentials :: cType
                                , name        :: nType} deriving (Show)

如何为FromRow编写UserRep个实例,以便postgresql-simple可以将查询转换为有用的类型?到目前为止,我有这个:

instance FromRow (UserRep a b) where
  fromRow = do
    username <- field
    password <- field
    fname <- field
    lname <- field
    return $ (User (Credentials username password) (Name fname lname))

导致此错误:

src/PSQLTEST.hs:30:5:
    Couldn't match type ‘a’ with ‘CredentialsRep uType0 pType0’
      ‘a’ is a rigid type variable bound by
          the instance declaration at src/PSQLTEST.hs:24:10
    Expected type: RowParser (UserRep a b)
      Actual type: RowParser
                     (UserRep (CredentialsRep uType0 pType0) (NameRep fType0 lType0))
    Relevant bindings include
      password :: pType0 (bound at src/PSQLTEST.hs:27:5)
      username :: uType0 (bound at src/PSQLTEST.hs:26:5)
      fromRow :: RowParser (UserRep a b) (bound at src/PSQLTEST.hs:25:3)
    In a stmt of a 'do' block:
      return $ (User (Credentials username password) (Name fname lname))
    In the expression:
      do { username <- field;
           password <- field;
           fname <- field;
           lname <- field;
           .... }
    In an equation for ‘fromRow’:
        fromRow
          = do { username <- field;
                 password <- field;
                 fname <- field;
                 .... }

src/PSQLTEST.hs:30:5:
    Couldn't match type ‘b’ with ‘NameRep fType0 lType0’
      ‘b’ is a rigid type variable bound by
          the instance declaration at src/PSQLTEST.hs:24:10
    Expected type: RowParser (UserRep a b)
      Actual type: RowParser
                     (UserRep (CredentialsRep uType0 pType0) (NameRep fType0 lType0))
    Relevant bindings include
      lname :: lType0 (bound at src/PSQLTEST.hs:29:5)
      fname :: fType0 (bound at src/PSQLTEST.hs:28:5)
      fromRow :: RowParser (UserRep a b) (bound at src/PSQLTEST.hs:25:3)
    In a stmt of a 'do' block:
      return $ (User (Credentials username password) (Name fname lname))
    In the expression:
      do { username <- field;
           password <- field;
           fname <- field;
           lname <- field;
           .... }
    In an equation for ‘fromRow’:
        fromRow
          = do { username <- field;
                 password <- field;
                 fname <- field;
                 .... }

1 个答案:

答案 0 :(得分:4)

(免责声明:我根本没有使用过这个库)

您尝试为所有FromRow定义UserRep a b,但在fromRow的定义中,您明确构建了UserRep (CredentialsRep u p) (NameRep f l),因此错误说它可以将aCredentialsRep u pbNameRep f l匹配(模数类型变量名称)。相反,我相信你可以做类似

的事情
instance (FromField u, FromField p, FromField f, FromField l) => FromRow (UserRep (CredentialsRep u p) (NameRep f l)) where
    fromRow = do
        username  <- field
        password  <- field
        firstname <- field
        lastname  <- field
        return $ User (Credentials username password) (Name firstname lastname)

或者只是

instance FromRow (UserRep (CredentialsRep String String) (NameRep String String)) where
    ...

具有相同的fromRow定义。使用此方法,您可能必须启用FlexibleInstances扩展名。

此外,看起来你可能会使你的类型过于多态(但你的情况可能是独一无二的,带着一点点的这个建议),你可以完全摆脱类型参数并拥有

data CredentialsRep = Credentials
    { username :: String
    , password :: String
    } deriving (Show)

data NameRep = Name
    { first :: String
    , last :: String
    } deriving (Show)

data UserRep = User
    { credentials :: CredentialsRep
    , name :: NameRep
    } deriving (Show)

在这种情况下你只需要

instance FromRow UserRep where
    ...

具有相同的fromRow定义。