有没有办法让函数根据输入 return 整数或字符串?
Is there a way for a function to return either ints or strings, depending on the input?
我收到了这个家庭作业(无法添加家庭作业标签)。这只是一个训练问题,不是上交的一部分。
我制作了一个递归函数“eval”,用于评估整数的常见操作(+、-、*、/)
至此,该函数可以计算加法、乘法和减法。
type expr =
| Const of int
| Add of expr * expr
| Mul of expr * expr
| Sub of expr * expr
let rec eval (n: expr): int =
match n with
| Const n -> n
| Add (a, b) -> eval a + eval b
| Mul (a, b) -> eval a * eval b
| Sub (a, b) -> eval a - eval b
此功能完美运行。接下来我必须扩展 expr 类型,以允许除法,通过添加:
| Div of expr * expr
我还需要通过创建一个新类型来处理除零的情况:
('a, 'b) result
这是新的 return 类型的评估(这在作业描述中,所以我必须这样做)。
这是我的尝试:
type ('a, 'b) result =
| Ok of int
| Err of string
let rec eval (n: expr): ('a, 'b)result =
match n with
| Const n -> Ok(Const n)
| Add (a, b) -> Ok(eval a + eval b)
| Mul (a, b) -> OK(eval a * eval b)
| Sub (a, b) -> Ok(eval a - eval b)
| Div (_, Const 0) -> Err "zero division"
| Div (a, b) -> Ok(eval a / eval b)
但我收到一条错误消息,指出操作符 +、-、* 和 / 没有为类型 ('a, 'b) 结果定义,这是有道理的。所以我的问题是,有没有办法让新类型继承其他类型?我无法输入如下内容:
type ('a, 'b) result =
| int
| Err of string
为什么这不是一回事?如果我在新类型中使用 int,是否必须指定一些关键字以便与 int 相关联? f# 想要相同的输出类型,无论输入如何,有没有办法解决这个问题?如果我没有创建新类型,我可以告诉函数输出是整数还是字符串?
简短的回答是否定的。
就像你说的 F# 只允许一种 return 类型。
在这种情况下,您的 result
类型有 2 组可能的值,Ok
值和 Error
值。
您的代码需要考虑这两种可能性,您不能忽略其中一种。
请记住 eval a
不再是 return 一个 int
,现在它 return 是一个 result
,里面可能有也可能没有 int
。
在 eval a
和 eval b
之后但在调用 +
、-
、*
或 /
之前,您需要检查如果任一结果是 Error
。只有当两者都是 Ok
时,您才能应用运算符。如果其中任何一个是 Error
你必须 return 错误,对吧?
您可以使用match
来检查(并提取int
),例如:
match eval a , eval b with
| Ok a', Ok b' -> Ok(a' + b')
| Error e , _
| _ , Error e -> Error e
记住你不需要复制上面的指令4次。
您可以创建一个函数并将运算符作为参数传递
使用此语法:(+)
、(-)
、(*)
、(/)
.
另一个提示:您只考虑除以 Const 0
的情况。
如果除以计算得出的 0
,例如 5/(1 - 1)
,会发生什么情况?
在函数式编程中有另一种方法来处理这个问题。
你最终需要的是一个 Bind
函数(或 Apply
)。
这个网站是了解它的一个很好的资源:https://fsharpforfunandprofit.com/rop/
你问的是 F# 是否允许你做类似的事情:
type Result = int | string
这不是一个不合理的期望,TypeScript 允许这样做。 F# 没有,它让你为每种情况定义一个新类型。
type Result = Ok of int | Err of string
当然,这在这种情况下有点烦人,但它确实使创建受歧视的联合更加自然 - 联合以某种方式“受歧视”,这里是通过它们的类型名称。在 TypeScript 中,您需要为每个 case 添加一个通用的 属性,这有点笨拙。
根本区别在于 F# 建立在名义上的 .NET 类型系统之上,而 TypeScript 是结构类型系统。 .NET 通过名称区分类型,TypeScript 通过内容区分类型。因此,您会发现自己在 F# 中创建了更多的类型名称。
我收到了这个家庭作业(无法添加家庭作业标签)。这只是一个训练问题,不是上交的一部分。 我制作了一个递归函数“eval”,用于评估整数的常见操作(+、-、*、/) 至此,该函数可以计算加法、乘法和减法。
type expr =
| Const of int
| Add of expr * expr
| Mul of expr * expr
| Sub of expr * expr
let rec eval (n: expr): int =
match n with
| Const n -> n
| Add (a, b) -> eval a + eval b
| Mul (a, b) -> eval a * eval b
| Sub (a, b) -> eval a - eval b
此功能完美运行。接下来我必须扩展 expr 类型,以允许除法,通过添加:
| Div of expr * expr
我还需要通过创建一个新类型来处理除零的情况:
('a, 'b) result
这是新的 return 类型的评估(这在作业描述中,所以我必须这样做)。 这是我的尝试:
type ('a, 'b) result =
| Ok of int
| Err of string
let rec eval (n: expr): ('a, 'b)result =
match n with
| Const n -> Ok(Const n)
| Add (a, b) -> Ok(eval a + eval b)
| Mul (a, b) -> OK(eval a * eval b)
| Sub (a, b) -> Ok(eval a - eval b)
| Div (_, Const 0) -> Err "zero division"
| Div (a, b) -> Ok(eval a / eval b)
但我收到一条错误消息,指出操作符 +、-、* 和 / 没有为类型 ('a, 'b) 结果定义,这是有道理的。所以我的问题是,有没有办法让新类型继承其他类型?我无法输入如下内容:
type ('a, 'b) result =
| int
| Err of string
为什么这不是一回事?如果我在新类型中使用 int,是否必须指定一些关键字以便与 int 相关联? f# 想要相同的输出类型,无论输入如何,有没有办法解决这个问题?如果我没有创建新类型,我可以告诉函数输出是整数还是字符串?
简短的回答是否定的。 就像你说的 F# 只允许一种 return 类型。
在这种情况下,您的 result
类型有 2 组可能的值,Ok
值和 Error
值。
您的代码需要考虑这两种可能性,您不能忽略其中一种。
请记住 eval a
不再是 return 一个 int
,现在它 return 是一个 result
,里面可能有也可能没有 int
。
在 eval a
和 eval b
之后但在调用 +
、-
、*
或 /
之前,您需要检查如果任一结果是 Error
。只有当两者都是 Ok
时,您才能应用运算符。如果其中任何一个是 Error
你必须 return 错误,对吧?
您可以使用match
来检查(并提取int
),例如:
match eval a , eval b with
| Ok a', Ok b' -> Ok(a' + b')
| Error e , _
| _ , Error e -> Error e
记住你不需要复制上面的指令4次。
您可以创建一个函数并将运算符作为参数传递
使用此语法:(+)
、(-)
、(*)
、(/)
.
另一个提示:您只考虑除以 Const 0
的情况。
如果除以计算得出的 0
,例如 5/(1 - 1)
,会发生什么情况?
在函数式编程中有另一种方法来处理这个问题。
你最终需要的是一个 Bind
函数(或 Apply
)。
这个网站是了解它的一个很好的资源:https://fsharpforfunandprofit.com/rop/
你问的是 F# 是否允许你做类似的事情:
type Result = int | string
这不是一个不合理的期望,TypeScript 允许这样做。 F# 没有,它让你为每种情况定义一个新类型。
type Result = Ok of int | Err of string
当然,这在这种情况下有点烦人,但它确实使创建受歧视的联合更加自然 - 联合以某种方式“受歧视”,这里是通过它们的类型名称。在 TypeScript 中,您需要为每个 case 添加一个通用的 属性,这有点笨拙。
根本区别在于 F# 建立在名义上的 .NET 类型系统之上,而 TypeScript 是结构类型系统。 .NET 通过名称区分类型,TypeScript 通过内容区分类型。因此,您会发现自己在 F# 中创建了更多的类型名称。