超越F#基础——工作流

超越F#基础——工作流

文/Robert Pickering  译/朱永光  出处/InfoQ

这篇文章是基于我之前为InfoQ撰写的名为《 超越F#基础——活动模式》的文章,介绍了另外一个新的语言特性——工作流。在F#的介绍性书籍,《F#基础》(2007 五月,由Apress出版)的11章中介绍了纵向语言编程方式——一种使用领域特定语言(Domain Specific Language,DSL)编写程序的技术。这些DSL也许通过使用文本或XML代表具体代码的方式,来被独立实现。通常,DSL应该通过某种数据结构和表达DSL的语言的其他特性,被完全地嵌入到通用编程语言的内部。工作流是建立在F#现有的强大纵向语言编程特性的基础上的一个特性。工作流允许你捕获一小段代码来检查其中的内容,这样的特点使函数库实现者有机会把工作流用于实现DSL的程序模块——一种类似于C# 3.0中的表达式树的技术。在这篇文章中,我们将深入研究一下F#中的工作流的工作原理。
相关厂商内容 使用ASP.NET控件封装Silverlight
移动数据库SQL Anywhere 10使用案例集锦
《IDC:SOA中国路线图》技术分析报告免费下载
SOA最佳实践之深入浅出SOA域模型
SOA最佳实践之BPEL简明手册

F#是一个针对.NET框架的静态类型化函数式编程语言。它具有OCaml常见的核心语言功能,以及其他流行的函数式编程语言的一些特性,并从很多其他编程语言获取了一些思想,包括Haskell、Erlang和C#。简而言之,这意味着F#是一个具有优雅语法的编程语言,当我们能交互式地执行代码的时候感觉有点像脚本编程,但是它都是类型安全且有着良好性能的编译语言。这篇文章不是F#的介绍文章,不过网络上有很多资源可以让我们容易地学习F#。可以参阅在我之前文章中的侧边栏所附加的一个“F#资源”列表。

创建工作流

工作流由两部分组成:用户定义的编排工作流实例的代码和定义工作流功能的函数库组件。让我们来看一个非常简单的工作流例子:

这里,我们看到一个“script”工作流绑定到一个“num”标识符上。这个工作流由两个部分组成,一部分是包含在花括弧中的F#表达式,另外一部分是以“script”作为标识符的前缀——它可以让人们了解这个工作流的实际功能。现在让我们来看看函数基础结构是如何让这个“脚本”工作的:

这个代码稍微有点多。让我们一块一块的分开,来看看它们各自是如何与我们最初的脚本一起工作的。首先,类型定义定义了我们脚本的类型。在这里,脚本即是一个产生值的函数。我们早先定义的脚本“num”具有Script类型,这是由于它本身就是一个在执行时会生成一个整数值的函数(在这个例子中,这个整数值是42)。接下来,我们定义了一个名为“runScript”的函数用于执行脚本,其也用于定义“delay”来在脚本执行之前延迟脚本的构造过程(这样,任何脚本中包含的负面影响都会在脚本被构造和执行时解决掉)。
这个函数组件的下一个主要部分是ScriptBuilder类。它定义了一些用于处理组成我们脚本的多个表达式的方法。这些表达式将被作为值交给这些方法处理。这里,“Return”和“Let”方法处理在这个脚本中的let和return操作。更有意思的是let操作。在let操作中“printfn”函数被用于打印出参数的值——这意味着当脚本执行时,let操作中的值被打印到了控制台上。这种方式对于帮助调试非常有用。最后,是得到ScriptBuilder类的实例。在这个实例中,“Script”被用于“num”工作流中。所以当“num”脚本被执行时:
runScript num如下内容输被出到控制台上:
2
21
val it : int = 42开始的两个值的执行let操作被打印出来的值,后面的值是F#交互机制自动打印出的这个函数的执行结果以及它的类型。
在工作流中,它不仅可以处理常规的F#表达式(如let操作),正如前面所演示的,也可以新建表达式,如“let!”(发音为let bang)和“yield”,以及其他的一些操作。这样的特性为工作流提供了真正强大的能力,允许函数库实现者创建这些关键字并赋予它们新的意义。
现在,我们将扩展一下这个例子来把“let!”表达式也包含进来。假设我们不想把每个let操作的结果都打印到控制台,只想让需要的操作被打印出来,则可以通过实现"let!"操作来提供一种变通的方法,允许程序员选择哪些操作被打印。下面是通过“ScriptBuilder”类中额外的方法来实现的,用于处理“let!”操作的代码:

我们也需要对“Let”做一小点修改,删除打印到控制台的代码:

那么现在当我们定义和允许脚本的时候,我们能使用let!操作来打印特定的let操作执行结果到控制台上:

现在,只有21会被打印到控制台:
21
val it : int = 42F#编译器是如何处理工作流和最终执行的表达式之间的转换过程的呢?这个过程可以被称作“反语法糖(de-sugaring)”,我们将在下一节重点讲述它的工作原理。

理解De-sugaring

工作流中的表达式可以被转化为利用“连续传递的风格(continuation passing style)”的数据结构,这一个过程就是所谓的“反语法糖”,相对而言工作流就是一种“语法糖(syntactic sugar)”。
理解“反语法糖”这个概念的最好起点还是应该回到我们那个简单例子:

被转化成:

这种优点——不必手工键入这些结构——是显而易见的。“加糖(sugared)” 的版本比既难于理解又容易出错的不加糖版本更短更容易理解和键入。比起一个原始的表达式,以这种形式完成表达式的优点是更加的灵巧。重点要注意的是“Bind”和“Let”方法被调用了。这些方法通过传入一系列参数而被调用——let操作作为第一个参数,接着以一个等待获取值的函数作为第二个参数。这样话,就可以让我们能取巧打印出参数“p”并接着把它传递给“rest”函数继续进行计算。在“Bind”方法的定义中可以看到如下代码:
printfn "%A" p
rest p这是在F#工作流非常核心的机制。连续风格的传递过程允许开发人员在一个值即将被赋值的时候插入额外的动作。在我们的例子中,这些动作稍微有点简单,但这些动作能在等待异步计算完成后被调用,然后接着执行——这就是我们将在这个系列的下一篇文章中所要讲到的异步工作流。

 

1. 用户与身体信息管理模块 用户信息管理: 注册登录:支持手机号 / 邮箱注册,密码加密存储,提供第三方快捷登录(模拟) 个人资料:记录基本信息(姓名、年龄、性别、身高、体重、职业) 健康目标:用户设置目标(如 “减重 5kg”“增肌”“维持健康”)及期望周期 身体状态跟踪: 体重记录:定期录入体重数据,生成体重变化曲线(折线图) 身体指标:记录 BMI(自动计算)、体脂率(可选)、基础代谢率(根据身高体重估算) 健康状况:用户可填写特殊情况(如糖尿病、过敏食物、素食偏好),系统据此调整推荐 2. 膳食记录与食物数据库模块 食物数据库: 基础信息:包含常见食物(如米饭、鸡蛋、牛肉)的名称、类别(主食 / 肉类 / 蔬菜等)、每份重量 营养成分:记录每 100g 食物的热量(kcal)、蛋白质、脂肪、碳水化合物、维生素、矿物质含量 数据库维护:管理员可添加新食物、更新营养数据,支持按名称 / 类别检索 膳食记录功能: 快速记录:用户选择食物、输入食用量(克 / 份),系统自动计算摄入的营养成分 餐次分类:按早餐 / 午餐 / 晚餐 / 加餐分类记录,支持上传餐食照片(可选) 批量操作:提供常见套餐模板(如 “三明治 + 牛奶”),一键添加到记录 历史记录:按日期查看过往膳食记录,支持编辑 / 删除错误记录 3. 营养分析模块 每日营养摄入分析: 核心指标计算:统计当日摄入的总热量、蛋白质 / 脂肪 / 碳水化合物占比(按每日推荐量对比) 微量营养素分析:检查维生素(如维生素 C、钙、铁)的摄入是否达标 平衡评估:生成 “营养平衡度” 评分(0-100 分),指出摄入过剩或不足的营养素 趋势分析: 周 / 月营养趋势:用折线图展示近 7 天 / 30 天的热量、三大营养素摄入变化 对比分析:将实际摄入与推荐量对比(如 “蛋白质摄入仅达到推荐量的 70%”) 目标达成率:针对健
1. 用户管理模块 用户注册与认证: 注册:用户填写身份信息(姓名、身份证号、手机号)、设置登录密码(需符合复杂度要求),系统生成唯一客户号 登录:支持账号(客户号 / 手机号)+ 密码登录,提供验证码登录、忘记密码(通过手机验证码重置)功能 身份验证:注册后需完成实名认证(模拟上传身份证照片,系统标记认证状态) 个人信息管理: 基本信息:查看 / 修改联系地址、紧急联系人、邮箱等非核心信息(身份证号等关键信息不可修改) 安全设置:修改登录密码、设置交易密码(用于转账等敏感操作)、开启 / 关闭登录提醒 权限控制:普通用户仅能操作本人账户;管理员可管理用户信息、查看系统统计数据 2. 账户与资金管理模块 账户管理: 账户创建:用户可开通储蓄卡账户(默认 1 个主账户,支持最多 3 个子账户,如 “日常消费账户”“储蓄账户”) 账户查询:查看各账户余额、开户日期、状态(正常 / 冻结)、交易限额 账户操作:挂失 / 解挂账户、申请注销账户(需余额为 0) 资金操作: 转账汇款:支持同行转账(输入对方账户号 / 手机号),需验证交易密码,可添加常用收款人 存款 / 取款:模拟存款(输入金额增加余额)、取款(输入金额减少余额,需不超过可用余额) 交易记录:按时间、类型(转入 / 转出 / 存款 / 取款)查询明细,显示交易时间、金额、对方账户(脱敏显示)、交易状态 3. 账单与支付模块 账单管理: 月度账单:自动生成每月收支明细,统计总收入、总支出、余额变动 账单查询:按月份、交易类型筛选账单,支持导出为 Excel 格式 还款提醒:若有贷款(简化版可模拟),系统在还款日 3 天前发送提醒 快捷支付: 绑定支付方式:添加银行卡(系统内账户)作为支付渠道 模拟消费:支持输入商户名称和金额,完成支付(从账户余额扣减) 支付记录:保存所有消费记录,包含商户、时间、金额、支付状态 4.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值