我有一个字符串列表:
[" ix = index"," ctr = counter"," tbl = table"]
我想从中创建一个元组,例如:
[("ix","index"),("ctr","counter"),("tbl","table")]
我什至尝试:
genTuple [] = []
genTuples (a:as)= do
i<-splitOn '=' a
genTuples as
return i
任何帮助都将被申请
谢谢。
最佳答案
Haskell的类型系统确实具有表现力,因此我建议从类型的角度考虑问题。这样做的好处是可以解决“自上而下”的问题,并且可以在进行过程中对整个程序进行类型检查,从而可以尽早捕获各种错误。通用方法是将问题逐步分解为较小的函数,每个函数最初保留为undefined
,但具有某种合理的类型。
您想要的是一个函数(我们称其为convert
),该函数接收字符串列表并生成元组列表,即
convert :: [String] -> [(String, String)]
convert = undefined
显然,输入列表中的每个字符串都需要解析为2个字符串的字符串。但是,解析可能会失败-纯粹的
String
类型不能保证您输入的字符串格式正确。因此,您的parse
函数可能返回一个元组。我们得到:parse :: String -> Maybe (String, String)
parse = undefined
我们可以立即使用
convert
将其插入到我们的mapMaybe
函数中:convert :: [String] -> [(String, String)]
convert list = mapMaybe parse list
到目前为止,还算不错-但
parse
实际上仍然是undefined
。假设它应该首先验证输入字符串是否为“ valid”,如果是,则将其拆分。所以我们需要valid :: String -> Bool
valid = undefined
split :: String -> (String, String)
split = undefined
现在我们可以定义
parse
:parse :: String -> Maybe (String, String)
parse s | valid s = Just (split s)
| otherwise = Nothing
是什么使字符串
valid
?假设它必须包含一个=
符号:valid :: String -> Bool
valid s = '=' `elem` s
为了进行拆分,我们将所有字符放在第一个元组元素的第一个
=
之前,其余的作为第二个元组元素。但是,您可能也想trim leading/trailing whitespace,所以我们需要另一个函数。现在,让我们使其成为无人值守trim :: String -> String
trim = id
使用此,我们终于可以定义
split :: String -> (String, String)
split s = (trim a, trim (tail b))
where
(a, b) = span (/= '=') s
请注意,我们可以在此处安全地调用
tail
,因为我们知道b
永远不会为空,因为总是有分隔符(这是valid
验证的内容)。从类型上讲,使用“非空字符串”表示此保证会很不错,但是可能有点过分设计。 :-)现在,有很多解决该问题的方法,这只是一个示例(并且可以使用eta reduction或现有库来缩短代码)。我试图说明的主要问题是,Haskell的类型系统允许您以类型指示的方式来解决问题,这意味着编译器从一开始就帮助您充实解决方案。
关于haskell - 在Haskell中将字符串列表转换为元组列表,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/28498844/