简体   繁体   English

如何在F#中使用区分联合编写算术表达式?

[英]How to write a arithmetic expression using a discriminated union in F#?

Recently, I started learning F# and I am a bit struggling with discriminated unions and function signatures. 最近,我开始学习F#,我对有区别的工会和功能签名有点挣扎。

I am trying to define an arithmetic expression (for sum, product, multiply, average etc) as a discriminate union and write a function that evaluates it. 我试图将一个算术表达式(求和,乘积,乘法,平均等)定义为一个判别联合并编写一个计算它的函数。 However, I can't figure out what I am doing wrong. 但是,我无法弄清楚我做错了什么。 Could anyone point me in the right direction? 有人能指出我正确的方向吗? This what I've tried so far: 这是我到目前为止所尝试的:

Attempt 1 尝试1

type Expr = 
    | Sum of int * int
    | Avg of int * int
    | Mul of int * int

let Evaluate (input : Expr)  =
    match input with
    | Sum(a,b) -> a + b

printfn "%A" (Sum(5,10))

My output is : 我的输出是:

Sum (5,10)

Attempt 2 尝试2

I also tried something like : 我也试过类似的东西:

type Expr = int -> int -> int

let evaluate (a : Expr) (b : Expr) = 
    match a,b with
    | a,b -> (fun a -> a + b)

printfn "%A" (evaluate 5 10)

since all common arithmetic expressions (like sum, product, multiply, average etc) take two integer inputs and output a single integer. 因为所有常见的算术表达式(如sum,product,multiply,average等)都需要两个整数输入并输出一个整数。

I am getting errors for: 'This expression was expected to have type Expr but here has type Int'. 我收到错误:'这个表达式预计有类型Expr但这里有类型Int'。

edit 1 编辑1

let evaluate (input : Expr)  =
    match input with
    | Sum(a,b) -> a + b
    | Avg(a,b) -> a + b / 2
    | Mul(a,b) -> a * b

let evaluate = function
    | Sum(a,b) -> a + b
    | Avg(a,b) -> a + b / 2
    | Mul(a,b) -> a * b

Attempt 1 looks about right but limited as it doesn't allow you to create expressions like 1+2+3 . 尝试1看起来正确但有限,因为它不允许您创建像1+2+3这样的表达式。

Instead you could try something like this: 相反,你可以尝试这样的事情:

type Expr =
  | Constant  of int
  | Add       of Expr*Expr
  | Sub       of Expr*Expr
  | Mul       of Expr*Expr
  | Div       of Expr*Expr

A bit more flexible and with support for bindings like x , y and so on: 更灵活,支持xy等绑定:

type Expr =
  | Constant  of int
  | Binding   of string
  | BinaryOp  of string*(int -> int -> int)*Expr*Expr
  | UnaryOp   of string*(int -> int)*Expr

Your first attempt comes close. 你的第一次尝试接近了。

type Expr = 
    | Sum of int * int
    | Avg of int * int
    | Mul of int * int

let evaluate = function
    | Sum(a,b) -> a + b
    | Avg(a,b) -> a + b / 2
    | Mul(a,b) -> a * b

As commented you left out the evaluation of the expression. 如评论所述,您遗漏了对表达式的评价。 Also there's no reason for using printfn "%A" , since we know the return type. 也没有理由使用printfn "%A" ,因为我们知道返回类型。

Sum(5,10)        // Expr
|> evaluate      // int
|> printfn "%i"  // unit

In your second attempt you're mixing things up a bit. 在你的第二次尝试中你会混淆一些东西。

type Expr = int -> int -> int

As Lee (again) correctly points out, this signature represents a function with 2 arguments. 正如李(再次)正确指出的那样,这个签名代表一个带有2个参数的函数。

let add : Expr = fun a b -> a + b

Or shorthand 或速记

let add : Expr = (+)

As Expr represents an arithmetic operator, following evaluate function combines them. 由于Expr表示算术运算符,因此以下evaluate函数将它们组合在一起。

let evaluate (a : Expr) (b : Expr) = 
    match a,b with
    | a,b -> (fun a -> a + b)
  • If you're intent was to sum two input integers, a and b should've been of type int. 如果你的目的是将两个输入整数相加,则a和b应该是int类型。
  • If you want to combine multiple expressions, FuneSnabel's proposal is the way to go. 如果你想结合多个表达式,FuneSnabel的提议就是你要走的路。

For example: (1 + 2) * (3 + 4) 例如:(1 + 2)*(3 + 4)

type Expr =
    | Cte of int
    | Add of Expr * Expr
    | Mul of Expr * Expr

let rec eval = function
    | Cte(i)   -> i
    | Add(a,b) -> eval a + eval b
    | Mul(a,b) -> eval a * eval b

Mul( Add(Cte 1,Cte 2) , Add(Cte 3,Cte 4) )
|> eval
|> printfn "%i"

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM