• F#学习笔记核心类型(一)


    前面介绍了.Net下的基本类型,但对于F#,还有些类型是非常重要的。

    Unit

    Unit代表着什么都不是,它的意思有点像C#的void,但是void不是类型,而Unit是个类型。在F#里可以定义一个Unit类型的值。因为F#里的方法必须有返回值,所以当我们的某个方法不需要返回任何结果的时候,就可以在方法的最后写上句 () 也就是返回一个Unit类型。

    let x = ();;

    val x : unit = ()

    在F#里提供了个ignore方法,它的作用是包装任意一个方法,使之返回Unit类型。

    let f x = x * x

    let y = ignore(f 10);;

    val f : int -> int
    val y : unit = ()

    Tuple 元组

    Tuple读作two-pull,元组是一组有序的数据。

    let x = (0, 1, –1);;

    val x : int * int * int = (0, 1, -1)

    let x = (0, (), "1", ("ab", 'c'));;

    val x : int * unit * string * (string * char) = (0, null, "1", ("ab", 'c'))

    当一个元组只有2个元素的时候,F#里有2个特殊的变量可以分别代表第一个元素以及第二个元素:

    let t = (0, 1)

    printfn "fst is %d, snd is %d" (fst t) (snd t);;

    fst is 0, snd is 1

    val t : int * int = (0, 1)

    当元组的元素不止2个的时候,你可以这样:

    > let t = (1, 2, 3)
    let x, y, z = t
    printfn "x is %d, y is %d, z is %d" x y z;;

    x is 1, y is 2, z is 3

    val t : int * int * int = (1, 2, 3)
    val z : int = 3
    val y : int = 2
    val x : int = 1

    现在我们来用Tuple来实现下add方法:

    > let add (x, y) = x + y;;

    val add : int * int -> int

    > add (1, 2);;
    val it : int = 3

    现在看起来有点点像C#里的方法,是吧:)

    另外:

    (1) = 1;;

    val it : bool = true

    List

    列表的定义:

    let lists = [“a”; "b”; "c”]

    let emptyList = [];;

    val lists : string list = ["a"; "b"; "c"]
    val emptyList : 'a list

    列表的常用一些操作:

    双冒号操作(::),添加一个元素到列表的表头。

    let lists = [1; 2; 3]

    let other = 0 :: lists;;

    val list : int list = [1; 2; 3]
    val other : int list = [0; 1; 2; 3]

    连接操作(&),将2个list合并。

    let x = [1; 3; 5; 7; 9]

    let y = [2; 4; 6; 8; 10]

    let z = x @ y;;

    val x : int list = [1; 3; 5; 7; 9]
    val y : int list = [2; 4; 6; 8; 10]
    val z : int list = [1; 3; 5; 7; 9; 2; 4; 6; 8; 10]

    List Range

    不知道这个特性该怎么翻译,在F#里,对于顺序的整数列表,提供了一种简便的定义方式。

    let x = [0 .. 10];; // 定义一个从0到10的列表

    val x : int list = [0; 1; 2; 3; 4; 5; 6; 7; 8; 9; 10]

    let x = [0 .. 10 .. 50];; // 定义一个从0 到50,间隔为10的列表

    val x : int list = [0; 10; 20; 30; 40; 50]

    let x = [0 .. 10 .. 49];; // 定义一个从0 到 49, 间隔为10的列表

    val x : int list = [0; 10; 20; 30; 40]

    let x = [10 .. –1 .. 0];; // 定义一个从10 到 0, 间隔为-1的列表

    val x : int list = [10; 9; 8; 7; 6; 5; 4; 3; 2; 1; 0]

    另外还可以通过表达式来定义列表:

    let list x =
        [
            yield x - 1
            yield x
            yield x + 1
        ]

    list 3;;

    val list : int -> int list

    val it : int list = [2; 3; 4]

    let list x =
        [
            for n in 0 .. x do
                if n % 3 = 0 then
                    yield n
        ];;

    list 15;;

    val it : int list = [0; 3; 6; 9; 12; 15]

    列表相关函数
    函数 类型 描述
    List.length 'a List –> int 返回List的长度
    List.head 'a List –> 'a 返回列表的第一元素
    List.tail 'a List –> 'a List 返回列表除第一个元素外的元素列表
    List.exists ('a –> bool) –> 'a List –> bool 返回是否存在满足条件的元素
    List.rev 'a List –> 'a List 反转列表后返回
    List.tryfind ('a –> bool) –> 'a List –> 'a opion 返回some(‘a)当满足的条件的时候,否则返回none
    List.zip 'a List –> 'b List –> ('a * ‘b) List 将2个相同长度的list,将其元素组成元祖,然后返回List
    List.filter ('a –> bool) –> 'a List –> 'a List 将list中满足条件的元素以list的形式返回
    List.partition ('a –> bool) –> 'a List –> ('a List * 'a List) 将list按照条件分为2个list,一个是满足条件的,一个是不满足的

    还有些更Powerful的函数:

    List.map

    通过一个'a –> 'b的函数,将列表转换成另一个列表。

    ('a –> 'b) –> 'a List –> 'b List

    借用下书中的图

    image

    比如,当有一个字符列表需要转换成byte列表,在C#里一般会写成:

    List<byte> bytes = new List<byte>();

    foreach(char c in chars) bytes.Add((byte)c);

    而在F#里可以更优雅的写成:

    > List.map (fun x -> byte x) ['a'; 'b'; 'c'];;
    val it : byte list = [97uy; 98uy; 99uy]

    List.reduce

    该方法接受一个'a –> 'a –> 'a的方法,依次遍历列表,将元素作为参数传递给该方法,并将方法的结果作为参数,以及下一个元素再次传给该方法,直至列表结束。

    比如,计算[1 .. 10]所有元素的和。

    List.reduce (fun x y –> x + y) [1 .. 10];;

    val it : int = 55

    计算过程可以理解为:

    1.let x = 1 + 2

    2.let x = x + 3

    3.let x = x + 4

    9.let x = x + 10

    10. x

    Btw,上面的代码还可以进一步简化,我们定义的 fun x y –> x + y其实等同于操作符'+’,所以我们可以写为:List.reduce (+) [1 .. 10];;,怎么样,是不是很简单呢

    List.fold

    List.reduce方法返回结果的类型同List的类型相同,可是当我们需要的结果类型跟List不同的时候,就需要List.fold方法了。比如我们要计算['a’; 'b’; 'c’]的ASCII码值的和。

    List.fold (fun x y –> x + (int y)) 0 [‘a’; 'b’; 'c’];;

    val it : int = 294

    List.reduceBack & List.foldBack

    这两个方法在《Programming F#》这本书里的描述是:"List.reduce and List.fold process the list in a left-to-right order. There are alternative functions List.reduceBack and List.foldBack for processing lists in right-to-left order. "。这段话,我理解了很久,做了一些测试,才理解了它的处理过程。

    List.reduceBack (-) [1 .. 5];;

    最开始,我以为它的结果应该是

    let x = 5 – 4

    let x = x - 3

    let x = x – 2

    let x = x – 1

    x // –5

    可是结果是:3。如果要得到3这个结果,我又猜测这个方法的执行方式是:

    let x = 2 – 1

    let x = 3 – x

    let x = 4 – x

    let x = 5 – x

    x // 3

    这回结果是对了,我又接着测试了下面的方法:

    List.reduceBack (+) ["a"; "b"; "c"; "d"; "e"];;

    如果按照上面的处理过程,结果应该是:“edcba”,可是结果是“abcde” ,看来前面又错了。这样的话,正确的执行过程应该是:

    let x = 4 – 5 // -1

    let x = 3 – x // 4

    let x = 2 – x // -2

    let x = 1 – x // 3

    x // 3

    现在来写个方法,把参数打印出来看看:

    let add x y =
        printfn "%d, %d" x y
        x + y
    List.reduceBack add [1 .. 5];;
    4, 5
    3, 9
    2, 12
    1, 14

    这回真的猜对了。其实是我笨,猜老半天,就没想到直接打出来看看,呵呵。

    唉,这个话题好长,写了3天了,还有个Option类型,实在不想写了。把这篇拆成2篇写好了。

    收工,睡觉~~

  • 相关阅读:
    3-2
    3-1
    2-11
    2-10
    2-7
    2-9
    springboot 使用undertow代替tomcat容器提高吞吐量
    springboot—JVM性能参数调优
    springbootDay3
    springboot_Mybaits_PageHelper
  • 原文地址:https://www.cnblogs.com/FMax/p/1739655.html
Copyright © 2020-2023  润新知