[英]Get column values from a Haskell Database
這是問題所在。 眾所周知,我是Haskell的新手,而聲明性語言部分與我以前所用的完全不同。 我已經建立了各種數據庫,用戶可以輸入“添加(用戶“名稱” )”或“創建(表“資金”)”之類的命令。 我正在嘗試創建一個函數,該函數將命令列表,用戶,表,列名(作為字符串)作為參數,並返回包含該列中的值的列表(如果用戶可以訪問它們的話)(例如,在命令列表中某處有一個匹配“允許(用戶名 )(表“資金”)”的命令。我們可以假定該表存在。
module Database where
type Column = String
data User = User String deriving (Eq, Show)
data Table = Table String deriving (Eq, Show)
data Command =
Add User
| Create Table
| Allow (User, Table)
| Insert (Table, [(Column, Integer)])
deriving (Eq, Show)
-- Useful function for retrieving a value from a list
-- of (label, value) pairs.
lookup' :: Column -> [(Column, Integer)] -> Integer
lookup' c' ((c,i):cvs) = if c == c' then i else lookup' c' cvs
lookupColumn :: [(Column, Integer)] -> [Integer]
lookupColumn ((c, i):cvs) = if null cvs then [i] else [i] ++ lookupColumn cvs
select :: [Command] -> User -> Table -> Column -> Maybe [Integer]
select a b c d = if not (elem (b, c) [(g, h) | Allow (g, h) <- a])
then Nothing
else Just (lookupColumn [(d, x) | Insert (c, [ (d, x ), _ ]) <- a])
我已經開始使用它,但是僅在某些情況下才可以使用。 現在,輸入的格式必須這樣,我們要從中獲取值的列必須是表中的第一列。 示例輸入如下。 運行: select example (User "Alice") (Table "Revenue") "Day"
返回的值應為Just [1,2,3]
,但是用Day
Amount
替換Day
無效。
example = [
Add (User "Alice"),
Add (User "Bob"),
Create (Table "Revenue"),
Insert (Table "Revenue", [("Day", 1), ("Amount", 2400)]),
Insert (Table "Revenue", [("Day", 2), ("Amount", 1700)]),
Insert (Table "Revenue", [("Day", 3), ("Amount", 3100)]),
Allow (User "Alice", Table "Revenue")
]
有關功能的一些解釋。 select
是應該返回該列中整數列表的函數。 現在,它僅與第一列匹配,但是我希望它可以與任意數量的列一起使用,而不希望用戶提前知道要使用哪一列。
[(d, x) | Insert (c, [ (d, x ), _ ]) <- a]
[(d, x) | Insert (c, [ (d, x ), _ ]) <- a]
返回僅與(Column,Integer)元組的每個列表中的第一個元組匹配的元組列表。
lookupColumn
接收一個元組列表,並返回其中的整數列表。 與lookup'
不同,我們知道接收的列表中只有正確的列(Column,Integer)元組。 lookup'
可以接受任意數量的元組的列表,但是必須檢查列名是否首先匹配。
任何幫助將不勝感激。
您的代碼中有一些奇怪的事情; 例如:
lookupColumn :: [(Column, Integer)] -> [Integer]
lookupColumn ((c, i):cvs) = if null cvs then [i] else [i] ++ lookupColumn cvs
在每種方式下鍵入的時間都比等效的map snd
(可能更快) map snd
。
此外,當您定義自己的數據結構時,通常元組是多余的。 你可以這樣寫:
data Command = Add User
| Create Table
| Allow User Table
| Insert Table [(Column, Integer)]
deriving (Eq, Show)
實際的問題是您的select
語句中的_
,該語句明確告訴Haskell放棄元組的第二個值。 相反,您需要一種可以捕獲與表關聯的所有(Column, Integer)
對的東西:
getCells :: [Command] -> Table -> [(Column, Integer)]
getCells db t = concat [cis | Insert t' cis <- filter isInsert db, t == t']
where isInsert (Insert _ _) = True
isInsert _ = False
(請注意,這使用的是我上面編寫的非Insert
版本的Insert
)。 有了這個,算法變得更加容易:
select :: [Command] -> User -> Table -> Column -> Maybe [Integer]
select db user table col
| Allow user table `elem` db = Just [i | (c, i) <- getCells db t, col == c]
| otherwise = Nothing
這里的大多數“工作”在做什么? 實際上,這只是我們在getCells
使用的concat :: [[a]] -> [a]
。 通過將表中所有行/ (Column, Integer)
所有(Column, Integer)
對連接在一起,我們可以非常輕松地抽出僅所需的列。
要做的事情:當有人說出Insert (Table "Revenue") [("Amount", 1), ("Amount", 2400)]
,阻止此代碼執行意外的操作,即使它僅在輸出中顯示為兩行來自一排。 您可以輸入正常化,效果很好,也可以返回[Maybe Integer]
,為沒有值的行提供空值(標准Prelude中的lookup
將代替concat
來完成您的工作您)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.