我使用以下类型来表示用户:
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;
.... }
答案 0 :(得分:4)
(免责声明:我根本没有使用过这个库)
您尝试为所有FromRow
定义UserRep a b
,但在fromRow
的定义中,您明确构建了UserRep (CredentialsRep u p) (NameRep f l)
,因此错误说它可以将a
与CredentialsRep u p
和b
与NameRep 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
定义。