F#学习之路(6)列表类型

来源:互联网 发布:西德尼谢尔顿 知乎 编辑:程序博客网 时间:2024/06/12 00:24

     列表在函数式编程中占据着重要的位置。在Lisp语言中,一切皆是列表,就连函数也是列表,列表在Lisp语言中发挥到了极致。F#语言列表语法来源于Ocaml,与Haskell语言也基本一致。本文只会讲解一些常用的使用方法,要很好的掌握列表,各位朋友可以google一下相关的内容。网络上对列表讨论比较深刻的大多以Haskell语言为例(Lisp语言列表很强大,但与大多数函数式语言列表的区别太大,不好借鉴)。

      一、如何定义列表

     在F#中定义一个列表,有几个方法。

     1、使用字量值

     


let l=[1;2;3]

let emptyList=List.empty

let lista=l @ emptyList

let listb=0::lista

     

     使用中括号'[',']',元素之间用分号分隔。不同于元组类型,元组使用'(',')',元素之间使用逗号分隔。

     F#中的列表是链表,列表元素必须是相同类型,列表是不可变的,因此定义后将不能改变。

     F#中定义一个空列表,有三种方法。它们在使用上有一些细微的差别。

     

printfn "%A" ((List.empty<int>).GetType()) 

printfn 
"%A" ((List.Empty:int list).GetType()) 

printfn 
"%A" (([]:int list).GetType())

     

     列表上定义了一个 @ 操作符,用于将一个列表追加到另一个列表的尾部,生成一个新的列表。而 :: 操作符,则将一个元素添加到一个列表的首部,形成一个新的列表。注意所有操作的列表本身不会改变。这种行为类似.net的string类型。

     

     2、使用范围表达式

 


let l1=[1..10]

let l2=[1..2..100]

let l3=['a'..'z']

     

     3、使用序列表达式

 

let l4=[for i in 1..10 do if  i>4 && i<8 then yield i]

     

     关于序列将在以后的博客中讨论,序列是一种计算表达式的实现。

 

     二、列表比较。

     

printfn "%b" ([1;2;3]>[1;2]) //true
printfn "%b" ([1;2]=[1;4]) //false

    

      列表类型可以很方便的进行值比较,要使用引用比较请使用obj.ReferenceEquals

     


printfn 
"%b" (obj.ReferenceEquals([],[])) //true
printfn "%b" (obj.ReferenceEquals([1],[1])) //false

 

     三、访问列表元素

     

printfn "%.2f" ([1.;2.].[1]) //2.00

 

     列表索引从0开始。

 

     四、使用列表类型属性     

     


printfn 
"%d" ([1..10].Length)  //10
printfn "%d" ([1;2;3].Head)   //1
printfn "%A" ([1;2;3].Tail)  //[2;3]
printfn "%A" ([1;2;3].IsEmpty) //false

 

     五、访问List模块操作列表 

 

 

Code

 

     上面的代码,使用namespace定义了一个FSharpLearning名称空间,使用type给int类型取了一个更有意义的名称LineNO。

     并且使用type定义了一个Order记录类型和Product记录类型,以及OrderStatus联合类型。

     之后使用module定义了一个子模块Order,并且这里使用[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]标注了Order模块。并告诉编译器在Order模块名后面加上Module作为模块名。前面说过顶层作用域不允许重名。

     Order模块中定义了几个函数,用来操作Order记录类型。之后,我们在ListTest模块中分别调用了这些定义的函数。

     List模块中函数较多,主要介绍三个,其它函数使用方法类似。

     


let numbers=[for i in 1..100 -> i]
numbers 
|>List.iteri (fun i num ->printfn "index %d:%d" i num)

      List.iteri函数类型为(int->'a->unit)->'a list->unit

      |>前向管道操作符。上面的字法等价于List.iteri (fun i num ->printfn "index %d:%d" i num) numbers

      List.iteri带有索引,还有一个List.iter不带索引,通常这两个函数用来遍历列表。

 

let number=[for i in 1..100 ->i]

numbers 
|>List.map (fun i->string i) |>printfn "%A"

     

     List.map的函数类型为('a->'b)->'a list->'b list

     map函数通常用来操作列表中每个元素,生成新的列表。 

 

let numbers=[for i in 1..100 ->i]

numbers 
|> List.reduce_left (+) |> printfn "%d"

 

     

     List.reduce_left函数类型为('a->'a->'a)->'a list ->'a

     reduce_left函数从左到右依次取出列表中两个元素操作。通常称为归约。

 

     六、列表与模式匹配

     

#light

let numbers=[for i in 1..100 -> i]

let rec print numbers=
    
match numbers with 
    
|[]->printfn "%s" ""
    
|[a]->printfn "%s" (string a)
    
|a::b ->printfn "%s" (string a);print b

print numbers

do System.Console.ReadKey(true)|>ignore

 

     总结:

     1、列表用于表示相同类型的一组数据的集合,在F#中大数据量集合类型应优先使用seq序列,因为序列是惰性的。

     2、列表是一个combinator,列表的类型定义为:

          type 'a list=

          |([])

          |( :: ) of 'a *'a list

     一个[1;2;3]的列表本质上是1::2::3::[],最具体的说是op_Cons(1,op_Cons(2,op_Cons(3,op_Nil)))

     op_Nil是[]的操作符名,op_Cons是::的操作符名。

     一个列表可以看作第一个元素(称为首部Head)与后面所有元素(称为尾部Tail)的组合。

     这样两个操作构成了列表的灵魂,深入研究组合子非常必要。

      下一篇:F#学习之路(7) 集合类型

 

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 人力资源模块 甘肃省人力资源和社会保障厅 甘肃省人力资源社会保障厅 山东省人力资源社会保障厅 人力资源大模块 人力资源社会保障部 四川省人力和社会保障厅 淄博市人力资源和社会保障网 甘肃人力资源社会保障厅 重庆人力和社会保障网 淄博市人力资源社会保障网 山东省人力资源保障厅 贵阳人力资源网 重庆人力社会保障网 重庆人力资源 广州市人力资源社会保障局 甘肃人力资源保障厅 广州市人力资源和社会保障局 人力社会保障局社保网 深圳市人力资源社会保障局 贵阳人力资源 深圳市人力资源和社会保障局 重庆市人力资源和社会保障局 青岛市人力资源和社会保障局 罗德岛人力资源部 河南省人力资源和社会保障厅 重庆人力资源和社保局网 潍坊市人力资源和社会保障局 台山人才人力资源网 河南省人力资源社会保障厅 重庆市人力资源社会保障局 潍坊市人力资源社会保障局 广州市人力资源保障局 深圳市人力资源保障局 北京市人力资源和社会保障局 重庆市人力资源社会保障网 成都市人力资源和社会保障局 北京市人力资源社会保障局 吴江人力资源 贵阳人力资源社会保障网 重庆市人力资源和社会保障网