2

在haskell中是否可以匹配复杂的模式?

我的意思是,我有一个逗号分隔值 (CSV) 文件:

name,ID,fieldA,fieldB

是否可以编写如下函数:

getName (n:',':xs) = n

哪里n不是单个元素而是列表?

4

4 回答 4

6

当我在 1980 年代还是个小男孩时,我实现了一种具有这种风格的复杂模式的函数式语言。这相当于在模式中允许++。生成的模式不明确,因此匹配涉及回溯搜索过程:程序员可以有效地指定是最小化还是最大化匹配 ++ 左侧模式的前缀长度。该语言具有“模式保护”的形式,因此可以测试候选匹配以查看后续计算是否成功并在失败的情况下被拒绝。由此产生的程序的含义通常是显而易见的。这很有趣。

这些天来,当遇到这样的问题时,我span会使用 ,如果这不能解决问题,我会使用解析器组合器。

span :: (a -> Bool) -> [a] -> ([a], [a])

span,应用于谓词 p 和列表 xs,返回一个元组,其中第一个元素是满足 p 的 xs 个元素的最长前缀(可能为空),第二个元素是列表的其余部分

因此,特别是span (/= ',')将 a 拆分String为第一个逗号之前的任何内容(如果没有逗号,则为整个内容)和其余部分(如果有逗号,则以逗号开头)。

如果那不会削减它,我会使用解析器组合器。

但我总是记得它曾经是多么容易。

于 2012-09-06T10:16:02.410 回答
3

你应该写一个函数来分割你的行......

import Data.List

parts = map tail . groupBy (/=) . (',':)

然后您可以轻松编写访问器函数:

getName xs = n where [n,_,_,_] = parts xs
getID   xs = i where [_,i,_,_] = parts xs
...

但与往常一样,使用数据类型会很好:

data Record = Record {getName :: String   
                     ,getId :: Int
                     ,getFieldA  
                     ,getFieldB :: String
                     } deriving Show 

initRecord xs = Record name (read id) fieldA fieldB where
                [name, id, fieldA, fieldB] = parts xs

当然,如果您需要错误处理,它会变得有点困难......

顺便说一句,那里有一个 Haskell CSV 库:http: //hackage.haskell.org/packages/archive/csv/0.1.1/doc/html/Text-CSV.html

于 2012-09-06T10:38:28.680 回答
2

您可以在列表元素上使用类似splitOnfromData.List.Split和模式匹配的内容。

> splitOn "," "a,b,c,d"
["a","b","c","d"]

它在拆分包中。

对于更复杂的事情,您可以使用 Parsec。

于 2012-09-06T10:37:39.943 回答
1

嗯,我不确定,但我不这么认为。为了解决您的问题,您可能应该在 Haskell 中查看一些关于正则表达式的内容。

于 2012-09-06T10:09:00.033 回答