将字符串列表转换为Haskell中的元组列表

时间:2015-02-13 11:44:17

标签: haskell

我有一个字符串列表:

[" ix = index"," ctr = counter"," tbl = table"]

我想从中创建一个元组,如:

[("ix","index"),("ctr","counter"),("tbl","table")]

我甚至尝试过:

genTuple [] = []
genTuples (a:as)= do
                   i<-splitOn '=' a
                   genTuples as
                   return i

任何帮助都会得到满足 谢谢。

2 个答案:

答案 0 :(得分:6)

Haskell的类型系统非常具有表现力,因此我建议从类型方面考虑问题。这样做的好处是你可以“自上而下”解决问题,并且可以随时对整个程序进行类型检查,这样你就可以及早发现各种错误。一般的方法是逐步将问题划分为较小的函数,每个函数最初都保留undefined,但有一些合理的类型。

你想要的是一个函数(我们称之为convert),它取一个字符串列表并生成一个元组列表,即

convert :: [String] -> [(String, String)]
convert = undefined

很明显,输入列表中的每个字符串都需要解析为2元组的字符串。但是,解析可能会失败 - 纯粹的类型String不能保证输入字符串格式正确。因此,您的parse函数可能会返回一个元组。我们得到:

parse :: String -> Maybe (String, String)
parse = undefined

我们可以使用mapMaybe

立即将其插入我们的convert函数中
convert :: [String] -> [(String, String)]
convert list = mapMaybe parse list

到目前为止,非常好 - 但parse仍然是undefined。假设它应该首先验证输入字符串是否为“有效”,如果是,则将其拆分。所以我们需要

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的类型系统允许您以类型为导向的方式处理问题,这意味着编译器可以帮助您从一开始就充实解决方案。

答案 1 :(得分:0)

你可以这样做:

import Control.Monda
import Data.List
import Data.List.Split

map ((\[a,b] -> (a,b)) . splitOn "=" . filter (/=' ')) [" ix = index"," ctr = counter"," tbl = table"]