14

我正在尝试读取包含以下形式的键/值对的文件:

#A comment
a=foo
b=bar
c=baz
Some other stuff

正如建议的那样,使用其他各种线路。这想进入一个地图,然后我可以从中查找密钥。

我最初的方法是读入行并拆分 '=' 字符以获得[[String]]. 在 Scala 中,我会使用collect,它接受一个部分函数(在这种情况下,类似于\x -> case x of a :: b :: _ -> (a,b)并将其应用到定义的地方,丢弃未定义函数的值。Haskell 是否有任何等价物?

如果做不到这一点,人们将如何在 Haskell 中做到这一点,无论是按照我的思路还是使用更好的方法?

4

2 回答 2

15

通常这是使用Maybe类型和完成的catMaybes

catMaybes :: [Maybe a] -> [a]

因此,如果您的解析函数具有类型:

parse :: String -> Maybe (a,b)

然后您可以通过将输入字符串解析为行、验证每一行并仅返回定义的值来构建映射:

Map.fromList . catMaybes . map parse . lines $ s

s你的输入字符串在哪里。

于 2013-03-26T10:24:45.633 回答
0

List Monad 提供了您正在寻找的内容。这可能最容易通过列表理解来利用,尽管它也适用于 do 表示法。

首先,这是供参考的 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发生的情况是模式匹配条件正在过滤掉使用from 方法不匹配的情况Monad

λ fail "err" :: [a]
[]

因此,列表理解和 do 表示法都在利用fail,这对这一点很不利 -

map (splitOn "=") xs >>= (
  \s -> case s of
    [k, v] -> return (k, v)
    _ -> fail ""
)
于 2017-02-22T02:14:03.990 回答