2012-02-29 73 views
0

我想CONVER bibtex entry到我自己的自定義數據類型,它看起來像:轉換中文提供進入到另一種數據類型

date MyEntry = MyEntry { 
    ident :: String, 
    author :: [String], 
    address :: String 
} 

但像authoraddress字段存儲的中文提供的字段數組中:

data T = 
Cons { 
    entryType :: String, 
    identifier :: String, 
    fields :: [(String, String)] 
} 
deriving (Show) 

上述會是這樣的一個例子:

Cons {entryType =「Book」,identifier =「Arrighi」,fields = [(「author」, 「Arrighi,Gino」),(「title」,「Leonardo Fibonacci:La Pratica di Geometria。 (Volgar izzata da Cristofano di Gherardo di Dino,cittadino pisano。Dal Codice 2186 dell a Biblioteca Riccardiana di Firenze。)/ A cino e con introduzione di Gino Arrigh i。「),(」address「,」Pisa「) ,(「發佈者」,「Domus Galilaeana」),(「date」,「1966」),(「note」,「(Testimonianze di storia della scienza,3)」),(「language」,「italian」 ),( 「pagetota L」, 「234」),( 「斷字」, 「意大利」)]}

如何可以在其上我的模式匹配將其轉換爲我的數據類型?

我被卡住了(這不起作用):

toEntry Cons { @entryType, @ident, @fields } = toEntry' entryType' ident fields' 

toEntry' entryType ident fs = MyEntry { ident, entryType, ???????? } 

回答

4

您可以按照@ehird描述的模式匹配記錄,但我想你也問過如何將「字段」列表轉換爲「作者」和「地址」字段。

您可以使用標準的前奏功能「查找」。它的工作原理如下:

lookup :: k -> [(k, v)] -> Maybe v 
lookup "a" [("a", 1), ("b", 2)] = Just 1 
lookup "c" [("a", 1), ("b", 2)] = Nothing 

如果沒有找到key或者「Just value」,它可能會返回「Nothing」。

所以,你可以在這兩種數據類型之間有這樣的轉換:

convert :: T -> MyEntry 
convert (Cons e i fields) = MyEntry i [auth] addr 
    where auth = fromMaybe "" (lookup "author" fields) 
     addr = fromMaybe "" (lookup "address" fields) 

在這裏,您將什麼到一個空字符串,這是通常不是一個好主意。因此,您可能需要將地址類型從「字符串」更改爲「可能字符串」,以考慮地址可能在原始字段中缺失的事實。

此外,您可能會遇到多個作者的問題,因爲「lookup」會返回第一個匹配鍵的值,這就是全部。要處理多個「作者」字段,可以編寫自定義查找函數或將字段列表轉換爲Data.Map,並將同一個鍵的值連接起來。以下是我如何(爲了允許多個地址,我已將地址類型更改爲列表):

data MyEntry = MyEntry { 
    ident :: String, 
    author :: [String], 
    address :: [String] 
} 

convert :: T -> MyEntry 
convert (Cons e i fields) = MyEntry i auth addr 
    where 
    fieldsMap = fieldsToMap fields 
    auth = lookupField "author" fieldsMap 
    addr = lookupField "address" fieldsMap 

-- lookup field and return an empty list if not found 
lookupField :: String -> Map.Map String [String] -> [String] 
lookupField = Map.findWithDefault [] 

-- convert each value into a list and then turn into a map, 
-- concatenating values with the same keys 
fieldsToMap :: [(String, String)] -> Map.Map String [String] 
fieldsToMap = Map.fromListWith (++) . map (\ (k, v) -> (k, [v])) 
+0

不用擔心多個作者。另外感謝 - 我想我會改變我的類型,讓'Maybe String'代替'String'。 – drozzy 2012-02-29 21:45:43

2

上以同樣的方式記錄你的模式匹配你寫了一個創紀錄的文字,只使用模式,而不是表達式:Constructor { field1 = pat, field2 = pat, ... }。例如:

toEntry Cons{entryType=et, identifier=i, fields=fs} = toEntry' et i fs 

toEntry' et i fs = MyEntry { ident = ..., author = ..., address = ... } 

您還可以對記錄使用標準構造函數語法。在這種情況下,它可能是更清楚省略了輔助功能,並使用標準的語法來代替:

toEntry (Cons et i fs) = MyEntry (...) (...) (...) 

另一種選擇是使用record puns(與{-# LANGUAGE NamedFieldPuns #-}),這讓你忽略模式(或表達中記錄文字),結合現場實至名歸:

toEntry Cons{entryType, identifier, fields} = ... 

此外,由於要綁定的所有字段,你可以使用record wildcards{-# LANGUAGE RecordWildCards #-}),它只是所有字段綁定到他們的名字:

toEntry Cons{..} = ... 

但是,在這種情況下,我的平淡的構造函數語法看起來不錯,我一般都不喜歡記錄雙關語,因爲它們影響字段訪問器(與字段名稱相同)。

+0

什麼是字段數組中的鍵值對?我不能構造'MyEntry'中途,然後處理這些... – drozzy 2012-02-29 21:14:33

+0

那麼,你問了模式匹配:)對於轉換字段,請參閱dying_sphynx的答案。 – ehird 2012-02-29 21:16:43

相關問題