簡體   English   中英

從Haskell數據庫獲取列值

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM