15.6.2 定义基元

来源:互联网 发布:宝宝发育软件 编辑:程序博客网 时间:2024/04/30 14:09

15.6.2 定义基元

 

    首先要定义将要处理的值类型,然后,实现几个可以在以后组合的基元。基元数据类型叫 Contract,表示可能出现在特定日期和时间的交易。

 

声明 CONTRACT 类型

 

    你可以看到在清单 15.23 中,Contract 类型与动画示例中的行为类型很相似,它是一个差别联合,只有一个识别器,名为 ContractFunc。这是我们一直在使用一种技巧,当定义行为时,它给了我们一种方法,可以创建简单、命名和封装的函数值。

 

Listing 15.23 Type representing financial contracts (F# Interactive)

 

> type Contract = 
     | ContractFunc of (DateTime -> seq<string * int>);; 
(...) 
> let eval_r(ContractFunc f) dt = f(dt) |> List.ofSeq;; 
val eval : Contract -> DateTime -> (string * int) list

 

    此函数表示实际合同带有一个参数,并返回一个元组序列。当我们用特定的日期调用它时,将生成所有发生在该日期的交易。每笔交易表示为一个元组,包含股票的名称和想要购买或出售的股票数量。我们将用正数表示购买股票数量,负数表示出售数量。

    清单15.23 的第二部分实现 eval 函数,计算在给定时间的合同,并返回的列表。我们使用一个序列来表示中的合同,因为,这会使代码更通用。我们看到动态生成序列并组合它们,是多么容易。Eval 函数返回一个列表,因为,从调用者的角度来看,更容易地处理。

 

实现组合

 

    有了表示我们的语言值的数据类型以后,就需要实现几个基本函数,来创建和组合这些值。对于行为,我们创建了基元值,比如,wiggle,和提升运算符来组合它们。在我们的合同语言中,从函数 trade 开始,创建一个表示可以发生在任何时间的购买合同。要组合合同,需要提供函数 combine,它把两份不同的合同加到这个交易中。

    清单 15.24 显示了这两个函数的实现,以及对于限定日期可能发生的合同的函数,和创建由合同所代表的我们准备出售股票交易的函数。

 

Listing 15.24 Combinators for creating and composing contracts (F# Interactive)

 

> let trade what amount = ContractFunc(fun _ –> 
     seq { yield what, amount }) 
   let combine (ContractFunc a) (ContractFunc b) = 
     ContractFunc(fun now –> 
       Seq.concat [ a(now); b(now) ]) 
;; 
val trade : int -> string -> Contract 
val combine : Contract -> Contract –> Contract

> let after dt (ContractFunc f) = ContractFunc(fun now –> 
     seq { if now >= dt then yield! f(now) }) 
   let until dt (ContractFunc f) = ContractFunc(fun now –> 
     seq { if now <= dt then yield! f(now) }) 
   let sell (ContractFunc f) = ContractFunc(fun now –> 
     seq { for itm, am in f(now) -> itm, -am }) 
;; 
val after : DateTime -> Contract -> Contract 
val until : DateTime -> Contract -> Contract 
val sell : Contract –> Contract

 

    可以在任何时间发生的单笔交易被表示为一个函数,将忽略其参数(我们计算合同的日期),并返回只有一个元素的序列。组合也简单,因为我们连接发生在给定日期的两个基础合同下所有的交易。

    接下来两个基元,在限定日期哪些合同是活动的。其实现是通过创建一个函数,测试给定的日期是否匹配基元的条件。当测试成功时,返回所有基础交易,使用 yield! 基元;否则,返回一个空序列。最后的基元可以用于修改合约是出售还是购买。 我们遍历一个合同的所有基础交易,把正的数量改为负,或相反。

    虽然我们只是大概地勾画出这个库,但已经实现的几个基元就能够描述许多有趣的情景了。