我正在尝试读取包含以下形式的键/值对的文件:
#A comment
a=foo
b=bar
c=baz
Some other stuff
如所建议的那样,有各种其他线路。这想要进入我可以从中查找键的地图。
我最初的方法是读取行并分成'='字符以获得[[String]]
。在Scala中,我将使用collect
,它采用部分函数(在这种情况下类似于\x -> case x of a :: b :: _ -> (a,b)
并将其应用于定义的位置,抛弃函数未定义的值.Haskell是否有任何值相当于这个?
如果不这样做,那么在Haskell中如何做到这一点,无论是沿着我的方向还是使用更好的方法?
答案 0 :(得分:14)
通常,这是使用Maybe
类型和catMaybes
:
catMaybes :: [Maybe a] -> [a]
因此,如果您的解析函数具有类型:
parse :: String -> Maybe (a,b)
然后您可以通过将输入字符串解析为行来构建映射,验证每一行并仅返回定义的值:
Map.fromList . catMaybes . map parse . lines $ s
其中s
是您的输入字符串。
答案 1 :(得分:0)
List Monad提供您正在寻找的内容。这可能最容易通过列表理解来利用,但它也适用于符号。
首先,这是Scala实现的参考 -
// Using .toList for simpler demonstration
scala> val xs = scala.io.Source.fromFile("foo").getLines().toList
List[String] = List(a=1, b=2, sdkfjhsdf, c=3, sdfkjhsdf, d=4)
scala> xs.map(_.split('=')).collect { case Array(k, v) => (k, v) }
List[(String, String)] = List((a,1), (b,2), (c,3), (d,4))
现在使用Haskell的列表理解版本 -
λ :m + Data.List.Split
λ xs <- lines <$> readFile "foo"
λ xs
["a=1","b=2","sdkfjhsdf","c=3","sdfkjhsdf","d=4"]
-- List comprehension
λ [(k, v) | [k, v] <- map (splitOn "=") xs]
[("a","1"),("b","2"),("c","3"),("d","4")]
-- Do notation
λ do { [k, v] <- map (splitOn "=") xs; return (k, v) }
[("a","1"),("b","2"),("c","3"),("d","4")]
正在发生的情况是,模式匹配条件是使用fail
中的Monad
方法过滤掉不匹配的案例。
λ fail "err" :: [a]
[]
因此,列表理解和符号都在利用fail
,这对此有所帮助 -
map (splitOn "=") xs >>= (
\s -> case s of
[k, v] -> return (k, v)
_ -> fail ""
)