1

我正在编写一些 mysql-simple 数据库代码,并且我正在使我的数据类型成为 QueryResults 类型类的成员,以便轻松解除它们。

但我最终得到了很多功能,比如:

data FullName {
  first_name :: String,
  middle_name :: String,
  last_name :: String
} deriving Show

newtype UID = UID Integer deriving Show

go :: [(String, String)] -> Maybe FullName
go fvs = do
  first  <- lookup "first_name" fvs
  middle <- lookup "middle_name" fvs
  last   <- lookup "last_name" fvs
  return $ FullName first middle last

go :: [(String, String)] -> Maybe UID
go fvs = do
  uid <- lookup "uid" fvs
  return $ UID (read uid)

查找只是返回的地方(也许是一个)。其中一些数据类型有十几列,所以这很乏味。

所以有很多这样的数据类型,我希望能够编写一个我会这样调用的函数:

go RealName ["first_name","middle_name","last_name"] fvs
go UID ["uid"] fvs

但我不知道这样的事情应该是什么类型,或者我将如何去做。也许这甚至是不可能的。

4

3 回答 3

3

使用Template Haskell,我怀疑您最终可能会得到如下代码:

makeGo ''FullName

扩展到

goFullName :: [(String, String)] -> Maybe FullName
goFullName fvs = do
  first  <- lookup "first_name" fvs
  middle <- lookup "middle_name" fvs
  last   <- lookup "last_name" fvs
  return $ FullName first middle last

顺便说一句:如果你import Control.ApplicativegoFullName可以写得更简洁,像这样:

goFullName :: [(String, String)] -> Maybe FullName
goFullName fvs
   = FullName <$> lookup "first_name" fvs
              <*> lookup "middle_name" fvs
              <*> lookup "last_name" fvs
于 2012-07-19T17:39:20.057 回答
2

我会把这个函数写成

import Control.Applicative

go :: [(String, String)] -> Maybe FullName
go fvs = FullName <$> l "first_name" <*> l "middle_name" <*> l "last_name"
    where l field = lookup field fvs
于 2012-07-19T17:47:44.067 回答
0

如果您的目标是最终获得QueryResults实例,为什么不这样做:

{-# LANGUAGE GeneralizedNewtypeDeriving,OverloadedStrings #-}

Module Main where

import Database.MySQL.Simple
import Database.MySQL.Simple.QueryResults
import Database.MySQL.Simple.Result
import Database.MySQL.Simple.Param

data FullName =
  FullName {
       first_name  :: String
     , middle_name :: String
     , last_name   :: String
  } deriving Show

newtype UID = UID Integer deriving (Show,Param)

instance QueryResults FullName where
  convertResults fs@[_,_,_] vs@[_,_,_] = FullName first middle last
    where [first,middle,last] = zipWith convert fs vs
  convertResults fs vs  = convertError fs vs 3

instance QueryResults UID where
  convertResults fs@[fuid] vs@[vuid] = UID (convert fuid vuid)
  convertResults fs vs  = convertError fs vs 1

uidToFullName :: UID -> IO FullName
uidToFullName (UID uid) =
  do conn <- connect defaultConnectInfo
     [fn] <- query conn
         "SELECT first_name,middle_name,last_name FROM user WHERE uid = ?" [uid]
     return fn

一个示例会话:

λ> :load Main.sh
λ> uidToFullName (UID 23)
FullName {first_name = "John", middle_name = "Horatio", last_name = "Smith"}

这是随附的 SQL:

CREATE TABLE user (
  uid Integer PRIMARY KEY,
  email Text,
  first_name Text,
  middle_name Text,
  last_name Text
);

INSERT INTO user VALUES (23,'john.horation@smith.com','John','Horatio','Smith');
于 2012-07-19T21:44:23.717 回答