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:
直接看例子吧:
Prelude> take 10 (cycle [1,2,3])
[1,2,3,1,2,3,1,2,3,1]
cycle的参数是一个列表:
看例子:
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]]
看例子吧:
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。
分享到:
相关推荐
Haskell是一种纯函数式编程语言,它的命名源自美国数学家Haskell Brooks Curry,他在数学逻辑方面上的工作使得函数式编程语言有了广泛的基础。Haskell语言是1990年在编程语言Miranda的基础上标准化的,并且以λ演算...
了解haskell的最简单明了的教程,图文并茂,不过是英文的,大家斟酌好再下。
haskell趣学指南。haskell的入门书,十分适合初学者。
Haskell 学习资料,Learn you a Haskell.
Learn You A Haskell For Great Good Mar 2011.pdf
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 ...
学习您的haskell笔记本:Jupyter改编的《 Learn a Haskell for Great Good!
本书是Learn you haskell for great good的中文电子版,方便阅读和查阅,是一本很好的工具书,对于Haskell入门来说很有帮助。
Haskell is one of the leading languages for teaching functional programming, enabling students to write simpler and cleaner code, and to learn how to structure and reason about programs. This ...
You will then learn about the basics of high frequency financial data mathematics as well as how to implement these mathematical algorithms in Haskell., You will also learn about the most popular ...
学习哈斯克尔 学习haskell 资料来源 向您了解Haskell( ) 学习Haskell( )
Learn_You_a_Haskell_for_Great_Good.pdf 英文版