【问题标题】:SML - Passing NONE or SOME as argumentSML - 传递 NONE 或 SOME 作为参数
【发布时间】:2025-12-24 12:50:15
【问题描述】:

我刚刚开始使用 SML,但在尝试将 NONE/SOME 作为参数传递给函数时遇到了麻烦。

fun fx (SOME x) (SOME y) f = f x y
    | fx (SOME x) (NONE) f = NONE
    | fx (NONE) (SOME y) f = NONE
    | fx (NONE) (NONE) f = NONE;

fun add x y = x + y;

fx (SOME 2) (SOME 4) add;

我要做的是仅当两个数字都不是 NONE 时才添加两个数字。但我收到以下错误:

Error: operator and operand do not agree [tycon mismatch]
  operator domain: int -> int -> 'Z option
  operand:         int -> int -> int
  in expression:
    ((fx (SOME 2)) (SOME 4)) add

如果去掉 NONE 的情况,即:

fun fx (SOME x) (SOME y) f = f x y

然后它工作正常。我不知道我到底在哪里犯了错误。 f 参数不是可选的,但它被视为一个。

【问题讨论】:

  • 重新定义fun add x y = SOME (x + y);怎么样?
  • add 只是一个例子,fx 对于任何需要两个操作数(加、乘等)的函数都是通用的

标签: smlnj


【解决方案1】:

您已经回答了“如何”,所以我将尝试解释“为什么”。

查看REPL中fx的类型:

val fx = fn : 'a option -> 'b option -> ('a -> 'b -> 'c option) -> 'c option

它产生一个'c option(从您的NONE 案例中知道结果是option 类型)。
(注意'a -> 'b -> 'c option'a -> ('b -> ('c option)),而不是('a -> 'b -> 'c) option。)

由于您的第一个案例是 f x y,因此它必须产生 option 类型 - 而 add 不会。

这就是错误信息想要表达的意思;因为SOME 2SOME 4int options,fx (SOME 2) (SOME 4) 的类型为(int -> int -> int option) -> int option(“运营商域”为int -> int -> int option),但addint -> int -> int
(这里使用“运营商”这个词有点混乱,你习惯了。)

如果您想要更通用的类型'a option -> 'b option -> ('a -> 'b -> 'c) -> 'c option,您需要包装结果(如您所见):

fun fx (SOME x) (SOME y) f = SOME (f x y)

【讨论】:

    【解决方案2】:

    就像 Nalin 在 cmets 中指出的那样,我不得不重新定义方法,只是不是在 add 上,而是在 fx 上。

    fun fx (SOME x) (SOME y) f = SOME (f x y)
    

    【讨论】:

    • 正确,通过包含返回 NONE 的选项,编译器期望所有返回的类型为 SOME 或 NONE。这就是返回整数或 NONE 失败的原因。 SMLNJ 是一种强类型语言!