`

Learn Haskell(二)

阅读更多

1.Ranges
有时候我们有这样一种需求:我们需要一个List,它的元素从1到20。从1到20敲出每一个元素肯定是一种可以搞定的办法,但肯定不是好办法。这时候,我们可以使用Haskell的Ranges来处理这种需求。
Ranges用来构建元素可以按照某种顺序枚举的List。像数字1,2,3,4就是可枚举的;字母a,b,c,d也是。我们看看两个Ranges的例子:上面说到的1-20,使用Ranges可以这样表示:

Prelude> [1..20]
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]

 同理,所有的小写字母可以这样表示:

Prelude> ['a'..'z']
"abcdefghijklmnopqrstuvwxyz"

 这只是最基本的,我们还可以设置Ranges的步进(step )。比如,我们需要一个含有1-20中所有偶数的List,我们可以这样:

Prelude> [2,4..20]
[2,4,6,8,10,12,14,16,18,20]

 但是需要注意的是,只能够设置一个步进,下面这种就不是Ranges了:

Prelude> [1,2,4,8..100]
<interactive>:5:9: parse error on input..'

 如果你不设置上限,那么得到的就是一个无限的List:

Prelude> [1..]
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27, 28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51, 52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75, 76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99, 100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117, 118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135, 136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153, 154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171, 172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189, 190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225, 226,227,228,229,230,231,232,233,234,235,236
......

 我们可以结合之前介绍的take函数,按你的要求获得指定数目的元素构成的List:

Prelude> take 5 [1..]
[1,2,3,4,5]

 这种方式是可行的,因为Haskell一旦得到了指定数目的元素就拉到了,不会去评估整个无限的List。 当然还有几个函数可以创建无限的List:

  • cycle函数

直接看例子吧:

Prelude> take 10 (cycle [1,2,3])
[1,2,3,1,2,3,1,2,3,1]

 cycle的参数是一个列表:

  • repeat函数

看例子:

Prelude> take 10 (repeat 5)
[5,5,5,5,5,5,5,5,5,5]

 repeat的参数是单个元素或者List:

Prelude> take 10 (repeat [1,2,3])
[[1,2,3],[1,2,3],[1,2,3],[1,2,3],[1,2,3],[1,2,3],[1,2,3],[1,2,3],[1,2,3],[1,2,3]]
 
  • replicate函数

看例子吧:

Prelude> replicate 3 5
[5,5,5]

 replicate创建一个含有a个元素b的List
需要特别指出的是,浮点数使用Ranges会出现精度问题。
2.List Comprehension
List Comprehension是一种过滤、转换和连接List的方式。List Comprehension与数学中集合的定义非常类似,比如:

要完成这样的工作,我们可以用之前提到take 函数:

Prelude> take 10 [2,4..]
[2,4,6,8,10,12,14,16,18,20]

 我们也可以使用List Comprehension的方式完成这个工作:

Prelude> [x*2|x<-[1..10]]
[2,4,6,8,10,12,14,16,18,20]

 这个的意思是,从List[1..10]中依次取出每个元素给x,然后x乘以2。在List Comprehension中,|左边的部分是输出,这一部分我们可以定义我们想要的输出是什么样子。感觉这种方式其实不是很方便,实际上List Comprehension更适合于比较复杂的问题。List Comprehension可以加条件。例如:

Prelude> [x * 2 | x <- [1..10], x > 5]
[12,14,16,18,20]

这个List Comprehension的意思很直接,1-10中,大于5的翻倍输出。条件是由, 隔开的,可以有多个。还可以在函数定义中使用List Comprehension:

let boomBangs xs = [ if x < 10 then "BOOM" else "BANG" | x <- xs, odd x]

 函数boomBangs接收一个List,将List中的大于10的奇数替换为"BANG",将小于10的替换为"BOOM"。我们可以使用一下这个函数:

Prelude> boomBangs [7..13]
["BOOM","BOOM","BANG","BANG"]

 我们还可以同时添加多个条件:

Prelude> [x | x <- [10..20], x /= 11,x /= 13, x /= 15]
[10,12,14,16,17,18,19,20]

 不仅条件可以添加多个,也可以同时从多个List中取值:

Prelude> [x * y | x <- [1,2,3], y <- [4,5,6]]
[4,5,6,8,10,12,12,15,18]

 再看几个例子:

 

Prelude> [x * y | x <- [2,5,10], y <- [8,10,11]]
[16,20,22,40,50,55,80,100,110]
Prelude> [x * y | x <- [2,5,10], y <- [8,10,11], x * y > 50]
[55,80,100,110]
Prelude> let nouns = ["hobo","frog","pope"]
Prelude> let adjectives = ["lazy","grouchy","scheming"]
Prelude> [adjective ++ " " ++ noun | adjective <- adjectives, noun <- nouns] ["lazy hobo","lazy frog","lazy pope","grouchy hobo","grouchy frog","grouchy pope","scheming hobo","scheming frog","scheming pope"]

 我们可以使用List Comprehension来实现一个length函数:

length' xs = sum [1 | _ <- xs]

 这个函数对于List xs中出现的每一个元素输出1,最后通过sum函数计算有多少个元素。再看一个去除字符串中小写字母的函数:

 

removeNonUppercase st = [ c | c <- st, c elem ['A'..'Z']] Prelude> let removeNonUppercase st = [ c | c <- st, c elem ['A'..'Z']]
Prelude> removeNonUppercase "Hahaha! Ahahaha!"
"HA"
Prelude> removeNonUppercase "IdontLIKEFROGS"
"ILIKEFROGS"

 

此外,List Comprehension也是可以嵌套的:

Prelude> let xxs = [[1,3,5,2,3,1,2,4,5],[1,2,3,4,5,6,7,8,9],[1,2,4,2,1,6,3,1,3,2,3,6]]
Prelude> [ [ x | x <- xs, even x ] | xs <- xxs]
[[2,2,4],[2,4,6,8],[2,4,2,6,2,6]]

 3.小结
看了这么多例子,个人感觉List Comprehension在处理一些比较复杂的情况很灵活,尤其是允许嵌套List Comprehension。

1
5
分享到:
评论

相关推荐

    haskell语言教程(learn you a haskell)

    2. 第二部分可能深入讲解函数、高阶函数和类型系统,包括类型类和类型推导。 3. 第三部分可能会涉及Monads,解释其工作原理和如何使用它们来管理副作用。 4. 第四部分可能包括IO操作,展示如何在纯函数式环境中进行...

    Get Programming with HASKELL

    By working through 43 easy-to-follow lessons, you'll learn Haskell the best possible way—by doing Haskell! Purchase of the print book includes a free eBook in PDF, Kindle, and ePub formats from ...

    learn you haskell

    Haskell 学习资料,Learn you a Haskell.

    Learn You A Haskell For Great Good Mar 2011.pdf

    ### 关于《Learn You A Haskell For Great Good》的知识点总结 #### 一、书籍基本信息概述 本书名为《Learn You A Haskell For Great Good》,是一本专为Haskell编程语言初学者编写的指南。作者是Miran Lipovaca,...

    learn your haskell的英文电子版

    http://learnyouahaskell.com/ 这个网站的pdf版,比较系统的haskell教程,不过是英文的

    learn-haskell:学习haskell

    为了学习Haskell,你可以参考《Haskell编程从入门到实践》、《Real World Haskell》等书籍,以及在线教程如"Learn You a Haskell for Great Good!"。此外,Stack Overflow、Haskell Cafe和Haskell subreddit等社区...

    学习您的haskell笔记本:Jupyter改编的《 Learn a Haskell for Great Good!

    《学习您的Haskell笔记本》是基于Jupyter Notebook的Haskell学习资源,改编自经典的Haskell教程《Learn You a Haskell for Great Good!》。这个项目旨在为Haskell初学者提供一个交互式的学习环境,通过Jupyter ...

    learn-haskell:探索Haskell

    在本文中,我们将深入探讨Haskell这一纯函数式编程语言,它是编程..."learn-haskell-master"这个项目可能是Haskell初学者的学习资源,包含教程、示例代码和练习,对于想要深入理解Haskell的人来说是一个很好的起点。

    haskell-first-principles:“基于第一原理的Haskell”的注释和实现

    《基于第一原理的Haskell》是一本深入探讨Haskell编程语言的著作,旨在通过解析Haskell的核心概念,帮助读者从基础出发理解这门函数式编程语言。Haskell以其纯净的函数式特性、静态类型系统和强类型推导而闻名,是...

    Learn_You_a_Haskell_for_Great_Good.pdf

    文档的标题“Learn_You_a_Haskell_for_Great_Good.pdf”和描述部分表明这本书是关于学习Haskell语言的入门指南。Haskell是一种高级的纯函数式编程语言,它具有强类型系统和惰性求值特性。它以其在编程语言理论领域的...

Global site tag (gtag.js) - Google Analytics