gpt4 book ai didi

f# - 与 AND 模式不完全匹配

转载 作者:行者123 更新时间:2023-12-04 18:09:30 24 4
gpt4 key购买 nike

我在 F# 中定义了一个表达式树结构,如下所示:

type Num = int
type Name = string
type Expr =
| Con of Num
| Var of Name
| Add of Expr * Expr
| Sub of Expr * Expr
| Mult of Expr * Expr
| Div of Expr * Expr
| Pow of Expr * Expr
| Neg of Expr

我希望能够漂亮地打印表达式树,因此我执行了以下操作:
let (|Unary|Binary|Terminal|) expr = 
match expr with
| Add(x, y) -> Binary(x, y)
| Sub(x, y) -> Binary(x, y)
| Mult(x, y) -> Binary(x, y)
| Div(x, y) -> Binary(x, y)
| Pow(x, y) -> Binary(x, y)
| Neg(x) -> Unary(x)
| Con(x) -> Terminal(box x)
| Var(x) -> Terminal(box x)

let operator expr =
match expr with
| Add(_) -> "+"
| Sub(_) | Neg(_) -> "-"
| Mult(_) -> "*"
| Div(_) -> "/"
| Pow(_) -> "**"
| _ -> failwith "There is no operator for the given expression."

let rec format expr =
match expr with
| Unary(x) -> sprintf "%s(%s)" (operator expr) (format x)
| Binary(x, y) -> sprintf "(%s %s %s)" (format x) (operator expr) (format y)
| Terminal(x) -> string x

但是,我真的不喜欢 failwith operator 的方法函数,因为它不是编译时安全的。所以我把它改写为一个事件模式:
let (|Operator|_|) expr =
match expr with
| Add(_) -> Some "+"
| Sub(_) | Neg(_) -> Some "-"
| Mult(_) -> Some "*"
| Div(_) -> Some "/"
| Pow(_) -> Some "**"
| _ -> None

现在我可以重写我的 format功能精美如下:
let rec format expr =
match expr with
| Unary(x) & Operator(op) -> sprintf "%s(%s)" op (format x)
| Binary(x, y) & Operator(op) -> sprintf "(%s %s %s)" (format x) op (format y)
| Terminal(x) -> string x

我假设,因为 F# 是魔法,所以这会起作用。不幸的是,编译器然后警告我不完整的模式匹配,因为它看不到任何匹配 Unary(x) 的东西。也将匹配 Operator(op)和任何匹配 Binary(x, y)也将匹配 Operator(op) .我认为这样的警告与编译器错误一样糟糕。

所以我的问题是:是否有特定的原因为什么这不起作用(比如我是否在某处留下了一些神奇的注释,或者有什么我没有看到的东西)?是否有一种简单的解决方法可以用来获得我想要的安全类型?这种类型的编译时检查是否存在固有问题,或者 F# 可能会在将来的某个版本中添加什么?

最佳答案

如果将基本术语和复杂术语之间的目的地编码到类型系统中,则可以避免运行时检查并使它们成为完整的模式匹配。

type Num = int
type Name = string

type GroundTerm =
| Con of Num
| Var of Name
type ComplexTerm =
| Add of Term * Term
| Sub of Term * Term
| Mult of Term * Term
| Div of Term * Term
| Pow of Term * Term
| Neg of Term
and Term =
| GroundTerm of GroundTerm
| ComplexTerm of ComplexTerm


let (|Operator|) ct =
match ct with
| Add(_) -> "+"
| Sub(_) | Neg(_) -> "-"
| Mult(_) -> "*"
| Div(_) -> "/"
| Pow(_) -> "**"

let (|Unary|Binary|) ct =
match ct with
| Add(x, y) -> Binary(x, y)
| Sub(x, y) -> Binary(x, y)
| Mult(x, y) -> Binary(x, y)
| Div(x, y) -> Binary(x, y)
| Pow(x, y) -> Binary(x, y)
| Neg(x) -> Unary(x)

let (|Terminal|) gt =
match gt with
| Con x -> Terminal(string x)
| Var x -> Terminal(string x)

let rec format expr =
match expr with
| ComplexTerm ct ->
match ct with
| Unary(x) & Operator(op) -> sprintf "%s(%s)" op (format x)
| Binary(x, y) & Operator(op) -> sprintf "(%s %s %s)" (format x) op (format y)
| GroundTerm gt ->
match gt with
| Terminal(x) -> x

另外,imo,如果您想要类型安全,您应该避免拳击。如果您真的想要这两种情况,请制作两种模式。或者,就像这里所做的那样,只需对您稍后需要的类型进行投影。通过这种方式,您可以避免装箱,而是返回打印所需的内容。

关于f# - 与 AND 模式不完全匹配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18047642/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com