Haskell 将bibtex条目转换为其他数据类型

Haskell 将bibtex条目转换为其他数据类型,haskell,Haskell,我想转换为我自己的自定义数据类型,它类似于: date MyEntry = MyEntry { ident :: String, author :: [String], address :: String } 但是像author和address这样的字段存储在bibtex的字段数组中: data T = Cons { entryType :: String, identifier :: String, fields :: [(String, Strin

我想转换为我自己的自定义数据类型,它类似于:

date MyEntry = MyEntry {
    ident :: String,
    author :: [String],
    address :: String
}
但是像
author
address
这样的字段存储在bibtex的字段数组中:

data T =
Cons {
   entryType :: String,
   identifier :: String,
   fields :: [(String, String)]
}
deriving (Show)
上面的例子如下:

date MyEntry = MyEntry {
    ident :: String,
    author :: [String],
    address :: String
}
Cons{entryType=“Book”,identifier=“Arrighi”,fields=[(“作者”, “Arrighi,Gino”),(“标题”,“莱昂纳多·菲波纳奇:实践” 几何学(西塔迪诺格拉多基督城沃尔加·伊扎塔) pisano.Dal Codice 2186戴尔a弗伦泽里卡迪亚纳图书馆。)/a 基诺阿里格博物馆 i、 (“地址”、“比萨”)、(“出版商”、“多莫斯”) 加利拉(Galilaeana),(“日期”、“1966年”),(“注释”),(“历史证明” scienza,3)”,(“语言”、“意大利语”),(“佩格托塔语”) “234”),(“连字号”,“意大利语”)]}

如何对其进行模式匹配以将其转换为数据类型

我立即陷入困境(这不起作用):


在记录上进行模式匹配的方式与编写记录文字的方式相同,只使用模式而不是表达式:
构造函数{field1=pat,field2=pat,…}
。例如:

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

toEntry' et i fs = MyEntry { ident = ..., author = ..., address = ... }
您还可以对记录使用标准构造函数语法。在这种情况下,省略helper函数并使用标准语法可能更清楚:

toEntry (Cons et i fs) = MyEntry (...) (...) (...)
另一个选项是使用(与
{-#LANGUAGE NamedFieldPuns#-}
),它允许您省略模式(或记录文本中的表达式),将字段绑定到其名称:

toEntry Cons{entryType, identifier, fields} = ...
此外,由于要绑定所有字段,因此可以使用(
{-#LANGUAGE RecordWildCards}
)将所有字段绑定到它们的名称:

toEntry Cons{..} = ...

但是,在这种情况下,我觉得普通构造函数语法很好的字段太少了,我通常不喜欢记录双关语,因为它们会隐藏字段访问器(与字段同名)。

您可以用编写记录文字的相同方式对记录进行模式匹配,仅使用模式而不是表达式:
构造函数{field1=pat,field2=pat,…}
。例如:

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

toEntry' et i fs = MyEntry { ident = ..., author = ..., address = ... }
您还可以对记录使用标准构造函数语法。在这种情况下,省略helper函数并使用标准语法可能更清楚:

toEntry (Cons et i fs) = MyEntry (...) (...) (...)
另一个选项是使用(与
{-#LANGUAGE NamedFieldPuns#-}
),它允许您省略模式(或记录文本中的表达式),将字段绑定到其名称:

toEntry Cons{entryType, identifier, fields} = ...
此外,由于要绑定所有字段,因此可以使用(
{-#LANGUAGE RecordWildCards}
)将所有字段绑定到它们的名称:

toEntry Cons{..} = ...

然而,在这种情况下,我觉得普通构造函数语法很好的字段太少了,我通常不喜欢记录双关语,因为它们会影响字段访问器(与字段同名)。

您可以按照@ehird所述对记录进行模式匹配,但我想您也询问了如何转换“字段”在“作者”和“地址”字段中列出

您可以使用标准的前奏功能“查找”进行此操作。其工作原理如下:

lookup :: k -> [(k, v)] -> Maybe v
lookup "a" [("a", 1), ("b", 2)] = Just 1
lookup "c" [("a", 1), ("b", 2)] = Nothing
如果找不到键,则返回“Nothing”,否则返回“Just value”

因此,您可以使用以下方法在这两种数据类型之间进行转换:

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,将同一个键的值串联起来。以下是如何(我已将地址类型更改为列表,以便也允许多个地址):


您可以按照@ehird所述对记录进行模式匹配,但我认为您还询问了如何将“字段”列表转换为“作者”和“地址”字段

您可以使用标准的前奏功能“查找”进行此操作。其工作原理如下:

lookup :: k -> [(k, v)] -> Maybe v
lookup "a" [("a", 1), ("b", 2)] = Just 1
lookup "c" [("a", 1), ("b", 2)] = Nothing
如果找不到键,则返回“Nothing”,否则返回“Just value”

因此,您可以使用以下方法在这两种数据类型之间进行转换:

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,将同一个键的值串联起来。以下是如何(我已将地址类型更改为列表,以便也允许多个地址):


那么字段数组中的键值对呢?我不能半途而废地构造MyEntry,然后再处理它们……好吧,你问过模式匹配:)要转换字段,请参阅Diing_sphynx的答案。字段数组中的键值对呢?我不能半途而废地构造MyEntry,然后再处理它们……好吧,你问过模式匹配:)要转换字段,请参阅Diing_sphynx的答案。不用担心多个作者。还谢谢-我想我会把我的类型改为
可能是String
,而不是到处都是
String
。不用担心多个作者。还谢谢-我想我会把我的类型改成
可能是String
,而不是到处都是
String