Я только начинающий программист Haskell (и маленький Haskell, который я узнал, был 5 лет назад), но для начала я напишу естественный перевод вашей функции с помощью аккумулятора («текущий абзац»)) передается вокруг (я добавил типы, просто для ясности):
type Line = String
type Para = [Line]
-- Takes a list of lines, and returns a list of paragraphs
paragraphs :: [Line] -> [Para]
paragraphs ls = paragraphs2 ls []
-- Helper function: takes a list of lines, and the "current paragraph"
paragraphs2 :: [Line] -> Para -> [Para]
paragraphs2 [] para = [para]
paragraphs2 ("":ls) para = para : (paragraphs2 ls [])
paragraphs2 (l:ls) para = paragraphs2 ls (para++[l])
Это работает:
*Main> paragraphs ["Line 1", "Line 2", "", "Line 3", "Line 4"]
[["Line 1","Line 2"],["Line 3","Line 4"]]
Так что это решение. Но тогда, Haskell опыт свидетельствует о том, что почти всегда есть библиотечные функции для делать вещи, как эти :) Одна из функций, связанных называются groupBy, и он почти работает:
paragraphs3 :: [Line] -> [Para]
paragraphs3 ls = groupBy (\x y -> y /= "") ls
*Main> paragraphs3 ["Line 1", "Line 2", "", "Line 3", "Line 4"]
[["Line 1","Line 2"],["","Line 3","Line 4"]]
К сожалению. Что нам действительно нужно, это «splitBy», и it's not in the libraries, но мы можем отфильтровать плохие сами:
paragraphs4 :: [Line] -> [Para]
paragraphs4 ls = map (filter (/= "")) (groupBy (\x y -> y /= "") ls)
или, если вы хотите быть прохладно, вы можете избавиться от аргумента, и сделать это в бесполезный способ:
paragraphs5 = map (filter (/= "")) . groupBy (\x y -> y /= "")
Я уверен, что существует еще более короткий путь.:-)
Edit: ephemient указывает на то, что (not . null)
чище, чем (/= "")
. Таким образом, мы можем написать
paragraphs = map (filter $ not . null) . groupBy (const $ not . null)
Неоднократное (not . null)
является сильным свидетельством того, что мы действительно должны аннотация на это в функцию, и это то, что делает Data.List.Split module, как указано в приведенной ниже ответ.
У вас есть ссылка на это? Отчет библиотеки Haskell 98 (http://www.cs.auckland.ac.nz/references/haskell/haskell-library-1.4-html/list.html) * говорит, что * это предикат равенства, но дает явную реализацию функция groupBy. Обратите внимание, что подпись типа groupBy не имеет ограничения «Eq», предполагая, что она должна работать с произвольной (транзитивной?) Предикатной функцией ... Похоже, что она используется так: http: //www.haskell .org/haskellwiki/List_function_suggestions # Generalize_groupBy_and_friends – ShreevatsaR
Я бы предпочел использовать 'not. null', чтобы использовать '(/ =" ")', что приведет к еще более свободным точкам 'paragraph = map (filter $ not. null). groupBy (const $ not. null) ' – ephemient