有没有办法让函数根据输入 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 aeval 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# 中创建了更多的类型名称。