如何在 F# 中使用可区分联合编写算术表达式?
How to write a arithmetic expression using a discriminated union in F#?
最近,我开始学习 F#,但在受歧视的联合和函数签名方面有些挣扎。
我正在尝试将算术表达式(求和、乘积、乘法、平均值等)定义为判别并集,并编写一个对其求值的函数。
但是,我无法弄清楚我做错了什么。谁能指出我正确的方向?这是我到目前为止尝试过的:
尝试 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))
我的输出是:
Sum (5,10)
尝试 2
我也试过类似的东西:
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)
因为所有常见的算术表达式(如求和、乘积、乘法、平均值等)都采用两个整数输入并输出一个整数。
我收到以下错误:'This expression was expected to have type Expr but here has type Int'。
编辑 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
尝试 1 看起来是正确的,但是有限制,因为它不允许您创建像 1+2+3
.
这样的表达式
相反,您可以尝试这样的操作:
type Expr =
| Constant of int
| Add of Expr*Expr
| Sub of Expr*Expr
| Mul of Expr*Expr
| Div of Expr*Expr
更灵活一些,支持 x
、y
等绑定:
type Expr =
| Constant of int
| Binding of string
| BinaryOp of string*(int -> int -> int)*Expr*Expr
| UnaryOp of string*(int -> int)*Expr
你的第一次尝试接近了。
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
如评论所述,您遗漏了表达式的计算。
也没有理由使用 printfn "%A"
,因为我们知道 return 类型。
Sum(5,10) // Expr
|> evaluate // int
|> printfn "%i" // unit
在你的第二次尝试中,你有点搞混了。
type Expr = int -> int -> int
正如 Lee(再次)正确指出的那样,此签名表示具有 2 个参数的函数。
let add : Expr = fun a b -> a + b
或shorthand
let add : Expr = (+)
由于Expr
表示一个算术运算符,下面的求值函数将它们结合起来。
let evaluate (a : Expr) (b : Expr) =
match a,b with
| a,b -> (fun a -> a + b)
- 如果您打算对两个输入整数求和,a 和 b 应该是 int 类型。
- 如果你想组合多个表达式,FuneSnabel 的建议是可行的。
例如:(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"
最近,我开始学习 F#,但在受歧视的联合和函数签名方面有些挣扎。
我正在尝试将算术表达式(求和、乘积、乘法、平均值等)定义为判别并集,并编写一个对其求值的函数。 但是,我无法弄清楚我做错了什么。谁能指出我正确的方向?这是我到目前为止尝试过的:
尝试 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))
我的输出是:
Sum (5,10)
尝试 2
我也试过类似的东西:
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)
因为所有常见的算术表达式(如求和、乘积、乘法、平均值等)都采用两个整数输入并输出一个整数。
我收到以下错误:'This expression was expected to have type Expr but here has type Int'。
编辑 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
尝试 1 看起来是正确的,但是有限制,因为它不允许您创建像 1+2+3
.
相反,您可以尝试这样的操作:
type Expr =
| Constant of int
| Add of Expr*Expr
| Sub of Expr*Expr
| Mul of Expr*Expr
| Div of Expr*Expr
更灵活一些,支持 x
、y
等绑定:
type Expr =
| Constant of int
| Binding of string
| BinaryOp of string*(int -> int -> int)*Expr*Expr
| UnaryOp of string*(int -> int)*Expr
你的第一次尝试接近了。
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
如评论所述,您遗漏了表达式的计算。
也没有理由使用 printfn "%A"
,因为我们知道 return 类型。
Sum(5,10) // Expr
|> evaluate // int
|> printfn "%i" // unit
在你的第二次尝试中,你有点搞混了。
type Expr = int -> int -> int
正如 Lee(再次)正确指出的那样,此签名表示具有 2 个参数的函数。
let add : Expr = fun a b -> a + b
或shorthand
let add : Expr = (+)
由于Expr
表示一个算术运算符,下面的求值函数将它们结合起来。
let evaluate (a : Expr) (b : Expr) =
match a,b with
| a,b -> (fun a -> a + b)
- 如果您打算对两个输入整数求和,a 和 b 应该是 int 类型。
- 如果你想组合多个表达式,FuneSnabel 的建议是可行的。
例如:(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"