Haskell эквивалент scala собирать - программирование
Подтвердить что ты не робот

Haskell эквивалент scala собирать

Я пытаюсь прочитать файл, содержащий пары ключ/значение формы:

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

С различными другими линиями, как это было предложено. Это хочет перейти на карту, на которой я могу найти ключи.

Мой первоначальный подход состоял бы в том, чтобы читать строки и делиться символом '=', чтобы получить [[String]]. В Scala я бы использовал collect, который принимает частичную функцию (в данном случае что-то вроде \x -> case x of a :: b :: _ -> (a,b) и применяет ее там, где она определена, выбрасывая значения, где функция undefined. Имеет ли Haskell какие-либо эквивалент этого?

В противном случае, как это сделать в Haskell, либо по моим линиям, либо с использованием лучшего подхода?

4b9b3361

Ответ 1

Обычно это делается с типом Maybe и catMaybes:

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

Итак, если ваша функция синтаксического анализа имеет тип:

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

то вы можете построить карту, разобрав входную строку в строки, проверив каждую строку и вернув только определенные значения:

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

где s - ваша строка ввода.

Ответ 2

Список 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, что desugars к этому -

map (splitOn "=") xs >>= (
  \s -> case s of
    [k, v] -> return (k, v)
    _ -> fail ""
)