码迷,mamicode.com
首页 > 其他好文 > 详细

第七章 F# 库(五)

时间:2014-07-22 23:03:12      阅读:314      评论:0      收藏:0      [点我收藏+]

标签:style   blog   http   color   使用   os   

第七章 F# 库(五)


事件(Microsoft.FSharp.Control.Event)模块

 

可以把 F# 中的事件看做是函数的集合,能够通过函数调用来触发。其思想是,函数本身注册成事件,即函数的集合,等待事件发生的通知;然后,触发函数发出事件已经发生的通知,引发所有添加到事件中的函数被执行。

我们将讨论事件模块中的下列功能:

创建和处理事件:使用 create 和 add 函数来创建和处理事件的基础;

筛选(filter)函数:筛选进入事件中数据的函数;

分区(partition)函数:把进入事件中数据拆分成两部分的函数;

映射(map)函数:在数据到达事件处理程序之前进行映射的函数。

 

 

创建和处理事件

 

第一个示例看一个简单的事件,通过调用事件(Event)对象的构造函数来创建,应该传递一个类型参数给构造,表示想要的事件类型;这个对象包含触发(Trigger)函数和表示事件本身的发布(Publish)属性。使用事件的 Publish 属性的 Add 函数添加处理程序方法,最后,用 Trigger 函数触发这个事件:

 

let event = new Event<string>()

event.Publish.Add(fun x -> printfn"%s" x)

event.Trigger "hello"

 

代码的运行结果如下:

 

hello

 

除了这个事件的基本功能之外,F# 的事件模块还提供了大量的函数,来筛选和分区事件,进行细粒度控制哪些数据传递给哪些事件处理程序。

 

 

筛选(filter)函数

 

下面的示例演示了如何使用事件模块的筛选函数,使数据在到达事件处理程序之前被筛选。在这个示例中,筛选那些以 H 开头的字符串数据发送给事件处理程序。

 

let event = new Event<string>()

let newEvent = event.Publish |>Event.filter (fun x -> x.StartsWith("H"))

 

newEvent.Add(fun x -> printfn "newevent: %s" x)

 

event.Trigger "Harry"

event.Trigger "Jane"

event.Trigger "Hillary"

event.Trigger "John"

event.Trigger "Henry"

 

代码的运行结果如下:

 

new event: Harry

new event: Hillary

new event: Henry

 

 

分区(partition)函数

 

事件模块的分区函数与筛选函数相似,只是它返回了两个事件,一个是分区函数返回假所触发的数据,另一个是分区函数返回真所触发的数据。下面的示例有演示:

 

let event = new Event<string>()

let hData, nonHData = event.Publish |>Event.partition (fun x -> true)

 

let x = Event.partition

 

hData.Add(fun x -> printfn "H data:%s" x)

nonHData.Add(fun x -> printfn "NoneH data: %s" x)

 

event.Trigger "Harry"

event.Trigger "Jane"

event.Trigger "Hillary"

event.Trigger "John"

event.Trigger "Henry"

 

代码的运行结果如下:

 

H data: Harry

None H data: Jane

H data: Hillary

None H data: John

H data: Henry

 

 

映射(map)函数

 

在数据到达事件处理程序之前进行转换也是可能的,这要乃至事件模块中提供的映射函数。下面的示例演示了如何使用:

 

let event = new Event<string>()

let newEvent = event.Publish |>Event.map (fun x -> "Mapped data: " + x)

newEvent.Add(fun x -> printfn"%s" x)

 

event.Trigger "Harry"

event.Trigger "Sally"

 

代码的运行结果如下:

 

Mapped data: Harry

Mapped data: Sally

 

这一节只对 F# 中的事件提供了一个概览,在第八章讨论用户界面编程时会有更详细的介绍,因为那才是事件的最主要用途。

 

 

功能包库 Fsharp.PowerPack

功能包(power pack)中有大量没有包含在FSharp.Core.dll 中的功能,这既有空间问题的原因,还因为它是带有试验性质,有可能比FSharp.Core.dll 的进化更快。它提供的模块能很好地与 OCaml 相兼容,有额外的集合,额外的数学函数,异步工作流(在第十章讨论),支持用fslex 和 fsyacc 进行文本解析的函数。下面我们就讨论Microsoft.FSharp.Math,这个命名空间包含了几个与数学相关的模块:任意精度的整数和理由、向量、矩阵和复数。

 

 

Microsoft.FSharp.Math命名空间

 

设计 Microsoft.FSharp.Math命名空间,是 F# 保证 F# 库包括了一些基础构造定义的使用更加广泛,如图形、数学、科学、工程等应用。首先,我们先简单地看一下这个模块的组成,然后,再分别看详细的示例。

它包含任意精度数,这是其值没有上限的数,包括在模块 BigInt 和 BigNum 中。典型的用途是在搜索大质数的程序中,可能用于加密应用。

模块 Matrix、Vector、RowVector 和 Notations 都包含了与矩阵和向量相关的运算。矩阵(Matrices)是按行列排列的一组数字集合,构成矩形数组;向量(Vectors)是一列数字,像只有一列的矩阵,但是单独的类型。向量的量由大小和方向描述,因此,二维向量由二个座标确定,三维向量由三个座标确定,等等。因此,向量的矩阵表示,由一列数字组成,而行数取决于向量的维度。

有一个模块 Complex,用于处理复数。复数(complex numbers)是许多不规则图形类型的基础,因此,我们会演示如何使用 F# 的复数库去画最著名的不规则图形,芒德布罗集合(Mandelbrot set)。反复迭代下面的等式,可以产生芒德布罗集合:

 

Cn+1 =Cn^2 + c

 

在这个序列中的下一个数等于当前数的平方加上起初数。如果反复迭代这个等式,停留在复数 C(1, 1i) 和 C(-1, -1i) 之间,那么起初复数就是芒德布罗集合的成员。下面的 F# 代码就能实现:

 

#r @"FSharp.PowerPack.dll"

open Microsoft.FSharp.Math

//openMicrosoft.FSharp.Math.Notation

 

let cMax = complex 1.0 1.0

let cMin = complex -1.0 -1.0

let iterations = 18

let isInMandelbrotSet c0 =

  let rec check n c =

    (n = iterations)

    || (cMin < c) && (c < cMax)&& check (n + 1) ((c * c) + c0)

  check 0 c0

 

[

1、需要引用 Fsharp.PowerPack;

2、没有且不需要 Microsoft.FSharp.Math.Notation 命名空间;

3、把or 要改成 ||

]

 

函数 isInMandelbrotSet 测试一个复数是否在芒德布罗集合中,通过递归调用 check 函数,每次用新 c 值计算 ((c * c) c0),直到这个复数在常量cMax 和 cMin 之间,或者迭代的次数超出常量 iterations。如果已经到达迭代次数iterations,那么这个数就是集合中的一个成员,否则,就不是。

因为复数由两个数字组成,因此,它可以用二维平面表示。芒德布罗复数介于 C(1, 1i) 和 C(-1, -1i) 之间,因此,画的这个平面要有一点原点,即点 0, 0,在中心,它的轴向两个方向延伸至最大值 1.0 和最小值 -1.0,如图 7-1 右边的平面。然而,当它应用到计算机屏幕上的像素时,必须考虑到平面的原点在左[原文为右]上角,向右、向下扩展。因为这种平面是由像素组成的,它是离散值,通常由整数表示,范围在 0 到 1600 之间,如图 7-1 左边的平面。

mamicode.com,码迷

图 7-1. 位图平面与复数平面

 

应用程序必须把位图平面的点映射到复数平面,这样,才可以知道一个像素是否是在这个复数平面中。

只用几行 F# 代码就能很容易实现这个映射:

 

open Microsoft.FSharp.Math

 

let scalingFactor = 1.0 / 200.0

let offset = -1.0

 

let mapPlane (x, y) =

  let fx = ((float x) * scalingFactor) + offset

  let fy = ((float y) * scalingFactor) + offset

  complex fx fy

 

一旦完成,只需要遍历位图平面上的所有点,用mapPlane 函数把它们映射到复数平面;然后,需要用isInMandelbrotSet 函数测试这个复数是否在芒德布罗集合中;最后,再设置像素的颜色。

完整程序如下:

 

open System

open System.Drawing

open System.Windows.Forms

open Microsoft.FSharp.Math

 

let cMax = complex 1.0 1.0

let cMin = complex -1.0 -1.0

let iterations = 18

 

let isInMandelbrotSet c0 =

  let rec check n c =

    (n = iterations)

    || (cMin < c)

    && (c < cMax)

    && check (n + 1) ((c * c) + c0)

  check 0 c0

 

let scalingFactor = 1.0 / 200.0

let offset = -1.0

 

let mapPlane (x, y) =

  let fx = ((float x) * scalingFactor) + offset

  let fy = ((float y) * scalingFactor) + offset

  complex fx fy

 

let form =

  let image = new Bitmap(400, 400)

  for x = 0 to image.Width - 1 do

    for y = 0 to image.Height - 1 do

      let isMember = isInMandelbrotSet ( mapPlane (x, y) )

      if isMember then

        image.SetPixel(x,y, Color.Black)

  let temp = new Form() in

  temp.Paint.Add(fun e ->e.Graphics.DrawImage(image, 0, 0))

  temp

 

[<STAThread>]

do Application.Run(form)

 

[

1、需要引用 Fsharp.PowerPack、System.Drawing、System.Windows.Forms;

2、如果使用交互模式,把 do Application.Run(form) 改成 form.ShowDialog()

]

 

图 7-2 是程序产生的芒德布罗集合图形。

 mamicode.com,码迷

图 7-2 芒德布罗集合

 

 

第七章 小结

 

在这一章我们讨论了许多基础知识,因为,F#库提供了多种不同功能。首先,我们浏览了 FSharp.Core.dll库中的Collections、Reflection、Math 模块;然后,看了一下FSharp.PowerPack.dll,提供了构建所有应用程序都需要使用的优秀函数。Seq 模块是任何实质性的 F# 程序所不能没有的。

接下来三章我们将讨论如何使用 F# 与各种 .NET API 一起完成常见的编程任务。首先,在第八章看一下实现用户界面,然后,在第九章关注数据存取,在第十章讨论分布式应用。


第七章 F# 库(五),码迷,mamicode.com

第七章 F# 库(五)

标签:style   blog   http   color   使用   os   

原文地址:http://blog.csdn.net/hadstj/article/details/24814025

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!