我正在尝试在标准ML中创建一个带有2个参数并返回bool的函数,并且2个参数可以是任何类型,在其编写的规范'a * 'a -> bool
中,但每当我尝试它时,它自动生成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
我该怎么做才能让它发挥作用?
答案 0 :(得分:6)
如果希望函数终止并返回值,则标准ML只有两个类型为'a * 'a -> bool
的函数。他们是
fun ktrue (_, _) = true
fun kfalse (_, _) = false
该类型的所有其他全部纯函数与上述两者无法区分。
这两个函数实际上具有更通用的类型'a * 'b -> bool
。
这实际上是编程语言理论的一个相当深刻的结果。如果你想学习基础,你可以尝试阅读John Reynolds关于表达独立性的工作或者Phil Wadler关于“自由定理”的工作。
答案 1 :(得分:0)
我相信这是我们可以用SML中的仿函数解决的问题。
例如,考虑是否存在一个名为TOTALORDER的签名,它在问题中定义了你的函数(lt意思是低于)。
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定义定义了一个带有两个函数(升序和降序)的签名。仿函数接收这种签名的实现作为参数。后来它使用它,在结构实现中按升序或降序对一对进行排序。
因此,最终,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等类型类别的其他语言相比,它肯定是冗长的,但我相信这是解决问题的有效方法。