1

我正在尝试在标准 ML 中创建一个函数,该函数接受 2 个参数并返回一个布尔值,并且 2 个参数可以是任何类型,在其编写的规范中,'a * 'a -> bool但每当我尝试它时,它都会自动生成 2 个参数整数。如何使函数采用 2 个类型为 'a.

以下是我试图实现的功能:

fun lessThan (a, b) = 
    if a < b then true
    else false;

但是在编写了上述函数之后,我得到的是:

val lessThan = fn : int * int -> bool

我想要的是这个:

val lessThan = fn : 'a * 'a -> bool

我该怎么做才能让它发挥作用?

4

2 回答 2

6

如果您希望函数终止并返回一个值,标准 ML 只有两个类型的函数'a * 'a -> bool。他们是

fun ktrue  (_, _) = true
fun kfalse (_, _) = false

该类型的所有其他完全纯函数与上述两个没有区别。

而这两个函数实际上具有更通用的类型'a * 'b -> bool

这实际上是编程语言理论的一个相当深刻的结果。如果您想学习基础知识,可以尝试阅读 John Reynolds 关于表示独立性的著作或 Phil Wadler 关于“自由定理”的著作。

于 2012-03-17T01:54:26.077 回答
0

我相信这是我们可以用 SML 中的函子解决的问题。

例如,考虑存在一个名为 TOTALORDER 的签名,它定义了您在问题中的函数(它的意思是低于)。

signature TOTALORDER = 
sig
    type element
    val lt: element * element -> bool
end

如您所见,函数定义为element * element -> bool,元素的类型在此处未定义。

然后我们可以定义两个不同的 TOTALORDER 实现来处理不同的类型,如下所示:

structure String : TOTALORDER =
struct
    type element = string
    fun lt(a:string, b) = a < b
end

structure Integer: TOTALORDER = 
struct
    type element = int
    fun lt(a, b) = a < b
end

上面我们定义了一个能够处理字符串的实现,以及另一个能够处理整数的实现。您可以看到,在这些实现中,我们定义了element.

现在我们可以在函子中定义可互换类型的魔力,如下所示:

functor MakeComparator(Lt: TOTALORDER):
    sig
        val descending : Lt.element * Lt.element -> Lt.element * Lt.element
        val ascending : Lt.element * Lt.element -> Lt.element * Lt.element
    end
    =
    struct
        open Lt;

        fun descending(a,b) = if lt(a,b) then (b,a) else (a,b)
        fun ascending(a,b) = if lt(a,b) then (a,b) else (b,a)
    end

在这里我们可以看到仿函数根据我们的 TOTALORDER 定义定义了一个带有两个函数的签名,称为升序和降序。函子接收这种签名的实现作为参数。后来它在 struc 实现中使用它以升序或降序对一对进行排序。

因此,最终,a 和 b 的类型取决于提供给函子的 TOTALORDER 的实现中元素的类型。

我们现在可以使用不同的比较类型创建不同的实现,如下所示:

structure StringComparator = MakeComparator(String)
structure IntegerComparator = MakeComparator(Integer)

我们可以将它们与它们的类型对应地使用。例如:

val res01 = StringComparator.ascending("arm","house") (*(arm,house)*)
val res02 = StringComparator.descending("arm","house") (*(house,arm)*)
val res03 = IntegerComparator.ascending(1,2) (*(1,2)*)
val res04 = IntegerComparator.descending(1,2) (*(2,1)*)

与具有类型类的 Haskell 等其他语言相比,它肯定是冗长的,但我相信这是解决问题的有效方法。

于 2013-04-22T16:08:17.403 回答