2012-07-19 47 views
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 

,但我不知道這樣的事情的類型應該是,或者我會怎樣去做。也許這是不可能的。

+0

'UID'需要一個'Integer',但你的(第二個)'go'函數似乎給它一個'String'。 (我認爲這兩個'go'函數應該有不同的名字。) – dave4420 2012-07-19 17:41:39

+0

你的'go'的第一個定義的類型爲[[(String,String)] - > Maybe FullName',你的第二個定義的類型爲'[(String ,String)] - >也許UID';如果你真的需要這個,你必須創建一個包含「'go :: [(String,String)] - > Maybe a'」的類型類併爲你的類型創建實例。 – Thedward 2012-07-19 18:00:05

+0

對不起,我忘了把閱讀內容放在我的測試代碼中。它被編輯。 – 2012-07-19 19:28:39

回答

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 
+0

我想到應用,我想這就像它得到的一樣好。 – 2012-07-19 20:37:47

+1

@mindreader - 你可能對'慣用括號'感興趣,它爲應用程序提供了一些語法糖。有幾種基於類型的實現(我更喜歡標準符號,但是YMMV),還有Strathclyde Haskell Enhancement,它被親切地稱爲「SHE」。 – 2012-07-20 02:15:27

2

如果你的目標是與QueryResults情況下結束了,我會寫這個功能

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 
0

,爲什麼不這樣做:

{-# 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 [email protected][_,_,_] [email protected][_,_,_] = FullName first middle last 
    where [first,middle,last] = zipWith convert fs vs 
    convertResults fs vs = convertError fs vs 3 

instance QueryResults UID where 
    convertResults [email protected][fuid] [email protected][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,'[email protected]','John','Horatio','Smith'); 
+0

我不想這樣做的原因是我希望能夠按任意順序進行選擇,只要它們的命名正確,並且其中足夠多,這樣我就可以從中獲得有效類型它。爲此,我必須讓convertResults不關心其參數的順序。 – 2012-07-20 13:03:13

相關問題