功能段落 [英] Functional paragraphs

查看:109
本文介绍了功能段落的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

对不起,我还没有得到FP,我想将一系列的行分割成一系列的行,假设一个空行作为段落分割,我可以像这样在python中完成:

  def get_paraghraps(行):
段= []
段= []

if line ==:#我知道它也可以是if line:
paragraphs.append(paragraph)
paragraph = []
else:
paragraph.append(line)
返回段落

你会怎么做在Erlang或Haskell中?

解决方案

我只是一个开始的Haskell程序员(我学习的Haskell是5年前的) ,但是一开始,我会写下你的函数的自然翻译,用累加器(当前段落)传递(为了清晰起见,我添加了类型):

 键入Lin e = String 
type Para = [Line]

- 取得一行行列表,并返回一段段落列表
段落:: [Line] - > [Para]
段落ls =段落2 ls []

- 辅助功能:取行的列表,以及当前段落
段落2 :: [行] - > Para - > [Para]
paragraph2 [] para = [para]
paragraph2(:ls)para = para:(paragraph2 ls [])
paragraph2(l:ls)para = paragraph2 ls (para ++ [l])

这样做:

  *主>段落[Line 1,Line 2,,Line 3,Line 4] 
[[Line 1,Line 2],[Line 3,Line 4]]






这是一个解决方案。但是,Haskell的经验表明,几乎总是有库函数来处理这样的事情:)一个相关的函数叫做

 段落3 :: [行]  - >       ; [Para] 
paragraph3 ls = groupBy(\ xy - > y / =)ls

* Main>段落3 [第1行,第2行,,第3行,第4行]
[[行1,行2],[, ,第4行]]

糟糕。我们真正需要的是splitBy,而它不在图书馆 ,但是我们可以自己过滤掉坏的:

 段落4 :: [行]  - > [b] 
paragraph4 ls = map(filter(/ =))(groupBy(\xy-> y / =)ls)
pre>

或者,如果你想变得很酷,你可以摆脱这个争论,并且以毫无意义的方式去做:

 段落5 =地图(过滤器(/ =))。 groupBy(\xy  - > y / =)

我确定有一个甚至更短的方式。 :-)

编辑 ephemient a>指出(not。null)(/ =)更干净。所以我们可以写成:

$ $ p $ 段落=地图(过滤$不.Null)。 groupBy(const $ not。null)

重复的 是一个强烈的暗示,我们真的应该把它抽象为一个函数,这就是 Data.List.Split模块,正如下面的答案中所指出的那样。


Sorry I don't quite get FP yet, I want to split a sequence of lines into a sequence of sequences of lines, assuming an empty line as paragraph division, I could do it in python like this:

def get_paraghraps(lines):
    paragraphs = []
    paragraph = []
    for line in lines:
        if line == "": # I know it could also be  "if line:"
            paragraphs.append(paragraph)
            paragraph = []
        else:
            paragraph.append(line)
    return paragraphs

How would you go about doing it in Erlang or Haskell?

解决方案

I'm only a beginning Haskell programmer (and the little Haskell I learnt was 5 years ago), but for a start, I'd write the natural translation of your function, with the accumulator ("the current paragraph") being passed around (I've added types, just for clarity):

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])

This works:

*Main> paragraphs ["Line 1", "Line 2", "", "Line 3", "Line 4"]
[["Line 1","Line 2"],["Line 3","Line 4"]]


So that's a solution. But then, Haskell experience suggests that there are almost always library functions for doing things like this :) One related function is called groupBy, and it almost works:

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"]]

Oops. What we really need is a "splitBy", and it's not in the libraries, but we can filter out the bad ones ourselves:

paragraphs4 :: [Line] -> [Para]
paragraphs4 ls = map (filter (/= "")) (groupBy (\x y -> y /= "") ls)

or, if you want to be cool, you can get rid of the argument and do it the pointless way:

paragraphs5 = map (filter (/= "")) . groupBy (\x y -> y /= "")

I'm sure there is an even shorter way. :-)

Edit: ephemient points out that (not . null) is cleaner than (/= ""). So we can write

paragraphs = map (filter $ not . null) . groupBy (const $ not . null)

The repeated (not . null) is a strong indication that we really should abstract this out into a function, and this is what the Data.List.Split module does, as pointed out in the answer below.

这篇关于功能段落的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆