【F#从入门到实战】05. F#表达式求值

举报
jackwangcumt 发表于 2021/04/29 14:03:07 2021/04/29
【摘要】 重点介绍如何用F#求表达式 ( a + x ) * b 的值

       欢迎大家来到【F#从入门到实战】,在这里我将分享关于F#编程语言的系列文章,带大家一起去学习和成长,并探索函数编程语言F#这个有趣的世界。所有文章都会结合示例代码和笔者的经验进行讲解,真心想把十余年的IT经验分享给大家,希望对您有所帮助,文章中也定有不足之处,请海涵!本系统文章将从F#基本语法入手,逐步通过自定义类型来实现数学表达式的各种常见解析操作,如对表达式进行求值、化简、展开、求导和求积分等。此系统博文也是了解和实现一个简易的计算机代数系统的基础。

      下面给出【F#从入门到实战】系统专题文章的目录:

【F#从入门到实战】01. F#语言快速入门 
【F#从入门到实战】02. F#数组常见用法   
【F#从入门到实战】03. F#自定义操作符 
【F#从入门到实战】04. F#5.0新特征总结 
【F#从入门到实战】05. F#表达式求值     
【F#从入门到实战】06. F#表达式化简    
【F#从入门到实战】07. F#表达式展开    
【F#从入门到实战】08. F#大整数阶乘    
【F#从入门到实战】09. F#表达式求导   
【F#从入门到实战】10. F#表达式积分   
【F#从入门到实战】11. F#库FParsec入门  
【F#从入门到实战】12. F#库FParsec解析表达式   
【F#从入门到实战】13. F#库FParsec实现求导符号计算   
【F#从入门到实战】14. F#实现分部积分法   

     下面将正式开始本文的介绍: 

     前一个博客简单对F#语言的基本情况和语法进行了一个概述,本篇则重点讲一次,如何用F#实现数学表达式的计算问题,当然了,F#还可以进行代数运算,比如求解微分和积分。这里我们先从简单的表达式开始,比如有一个表达式 ( a + x ) * b ,当 a = 1,b = 3,x = 2时,如何求出该表达式的值。

    这里为了更加通用,并不能定义一个f(a,b,x) =  ( a + x ) * b,而这个表达式可变的,比如 x * 2 或者 (x + 2) * (x + 3 ) 。因此,这里需要定义一个自定义的表达式数据类型:

type Expr = 
  | CstF of float
  | Var of string
  | Add of Expr * Expr  // +
  | Sub of Expr * Expr // -
  | Mul of Expr * Expr // *
  | Div of Expr * Expr // / 
;;

    其中的type关键字定义了一个数据类型Expr , 其中包含CstF常数,这里定义一个float类型的,如2.8,整数的化,可以表示为2.0 。Var 代表一个变量类型,它是一个字符串类型,比如"x" 。定义一个变量可以用 Var "x"表示。

    Add 代表 四则运算中的加法操作,它接收两个参数,都是 Expr。同理,Sub代表减法,Mul代表乘法,Div代表除法。当然其他的操作可以根据需要进行扩展,比如Sin of Expr 。下面给出几个表达式的定义示例:

let e1 = CstF 7.;; // 7.0
let e2 = Add(CstF 3.0, Var "x");; // 3.0 + x
let e3 = Mul(e2, Var "a");; // (3.0 + x) * a

    回到之前提到的问题,如何用F#求表达式 ( a + x ) * b 的值,其中的a , b ,x 在计算的时候,需要指定具体的参数值,比如 a = 7.2,b = 6.5,x = 3.0。首先需要给出一个上下文变量的容器:

(* 上下文变量 (string * float) list *)
let env = [("x", 3.); ("a", 7.2); ("b", 6.5); ("c", 2.)];;

    有了这个上下文环境标量列表,定义一个查找的函数,来根据变量来查询变量值,比如 变量 x 返回 3.0 。

//从上下文环境中查找变量值
let rec lookup env x =
    match env with 
    | []        -> failwith (x + " not found")
    | (y, v)::r -> if x=y then v else lookup r x;;

    这个查找函数是一个递归函数,它会每次取出列表的一个元素,并进行查找,如果找到,则返回变量值,如果未找到,则继续从剩余的列表元素中查找变量值。下面则定义一个执行计算的的函数:

(* 计算 *)
let rec eval e (env : (string * float) list) : float =
    match e with
    | CstF f            -> f
    | Var x             -> lookup env x 
    | Add(e1, e2) -> eval e1 env + eval e2 env
    | Mul(e1, e2) -> eval e1 env * eval e2 env
    | Sub(e1, e2) -> eval e1 env - eval e2 env
    | Div(e1, e2) -> eval e1 env / eval e2 env
    | _          -> failwith "unknown operation";;

    这里用到模式匹配的强大功能,这里需要注意,匹配的规则是有顺序的,它只要匹配到一条后,就会返回结果。因此,越是具体的,详细的,越是要放前面,抽象的,复杂的,放下面。


02.jpg

  执行表达式求值,则结果如下:


03.jpg

  下一步将重点介绍一下,如何对表达式进行化简操作,比如 ( a + x ) + ( a - x ) -> 2*a  。





【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。