我有一个字符串列表:

[" 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/

10-11 22:34
查看更多