通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。
通过显式提供的回调函数使用事件,并不是非常声明性的,我们是用命令式添加事件处理程序,且把整个行为打包在回调函数里面。那么,怎样把事件看成是更具声明性方式呢?我们已经看到过,声明性代码中的一个重要技术是使用高阶函数。最好的例子是处理列表的函数,比如List.filter、List.map 或 List.fold。如果我们有一个来自文件系统监视程序(称为 watcherEvents)的事件列表,可以把这些代码拆分成两个部分。第一部分把事件的源格式转换成适宜打印的格式,这部分可以用声明式风格来写,使用高阶函数处理列表。第二部分可以用简单的命令式代码,打印信息。这种方法的主要好处是,大部分代码用声明式风格来写。特别是,筛选的代码将如下所示:
let renamedVisible =
watcherEvents |> List.filter isNotHidden
这个代码段使用的 isNotHidden 函数,是作为参数传递给筛选列表的函数。第二部分可以使用 List.iter 来打印每个列表中的项。这只是我们熟悉的使用列表方式,但清单 16.2 显示了完整的示例,正是用这种模式来处理事件的。我们可以把事件当成与列表类似:两者都表示序列值,所不同的是,事件中的值不是立即可用,而是每当事件触发时,才会出现一个新值。这个事件参数的序列可以用类似处理集合的方式进行筛选。Observable.filter 函数创建一个事件,当源事件生成的值匹配给定的断言时触发。
Listing 16.2 Filtering events using the Observable.filter function (F# Interactive)
> let renamedVisible =
fileWatcher.Renamed |> Observable.filter isNotHidden
;;
val renamedVisible : System.IObservable<RenamedEventArgs>
> renamedVisible |> Observable.add (fun fse –>
printfn "%s renamed to %s" fse.OldFullPath fse.FullPath);;
val it : unit
第一个命令筛选事件,与筛选列表值的方式非常相似,返回的事件侦听文件系统监视程序的事件,当文件重命名时,它使用指定的筛选函数,测试由事件携带的值是否应该忽略。如果筛选函数返回 true,会触发结果事件;否则,将忽略当前发生的事件。
表示返回事件值的类型,需要更多的解释,我们得到了的值,是 .NET 4.0 新的类型 System.IObservable<'T>,它已添加了处理对象的统一方法,即,需要通知其他状态改变的对象。在上一节,我们写的 F# 中的事件,其值为 IEvent<'T> 类型,所以,你可能想知道,为什么我们在这里没有看到 IEvent<'T>。让我们先看一下清单的其余部分,再详细讨论这两种类型些之间的关系。在列表中的最后一个命令注册了 lambda 函数,使用筛选的事件,打印有关重命名文件的信息。我们使用另一个处理事件的函数,Observable.add,这个函数的行为,与 IEvent <'T> 类型的 Add 方法类似,我们先前使用过。当使用 IObservable<'T > 时,我们将把整个事件处理代码,用高阶函数,写成一个流操作。现在,让我们来更详细看看,在 F# 中,事件和事件值的表示方式。