我有一个字符串列表:
[" ix = index"," ctr = counter"," tbl = table"]
我想从中创建一个元组,如:
[("ix","index"),("ctr","counter"),("tbl","table")]
我甚至尝试过:
genTuple [] = []
genTuples (a:as)= do
i<-splitOn '=' a
genTuples as
return i
任何帮助都会得到满足 谢谢。
答案 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"]