在SML中(具体来说,我使用的是SML / NJ)我可以编写一个简单的多态相等函数。例如:
fun mem (x, []) = false
| mem (x, y::l) = (x=y) orelse mem (x, l);
但是,如果我想为另一个运算符(例如大于运算符)执行相同的操作,该怎么办?例如,如果我希望以下函数能够接受Ints,Chars和Strings,那该怎么办?
fun greater (x, []) = false
| greater (x, y::l) = (x>y) orelse greater (x, l);
有没有办法做到这一点?
编辑:更大功能的拼写错误
答案 0 :(得分:3)
假设您要使用<
运算符,请执行。运算符<
不是真正的多态,而是以标准ML中不可扩展的方式重载。这与=
不同,它支持新类型的重载。 =
的类型为''a * ''a -> bool
,可以理解为:鉴于'a
是一种可以进行相等性比较的类型,=
需要两个这种类型的值并返回bool类型的值。当然,并非所有多态值都可以进行相等性比较。功能就是一个例子。
通过某个属性对某些多态值进行分组(例如,相等或排序的比较)的概念在Haskell中称为类型类,而标准ML的相等类型是唯一的类型标准ML支持的类。
当您查看<
的类型时,它可能是int * int -> bool
或string * string -> bool
,或者是第三种类型,具体取决于上下文。如果标准ML支持例如,它将是整洁的'''a
表示可以订购的多态值。但是这个符号在前两个或三个类型类之后变得乏味,而且一个类型在does what Haskell does之后徘徊。
最简单的替代方法是为一些具体类型t * t -> order
传递一个排序函数t
,其中order
是值为LESS
的内置类型, EQUAL
和GREATER
(看起来比bool
稍微偏见,但从长远来看更好)。将这样的比较运算符传递给需要比较任意类型的所有函数时,最终会变得很烦人,因为你为很多类型和很多函数做了这个,你可以创建一个签名,
signature ORDERABLE =
sig
type t
val compare : t * t -> order
end
并且每当您需要对可订购的东西执行通用操作时,例如把它们放到二叉树中,就可以创建一个仿函数,
functor BinTree (SomeOrd : ORDERABLE) =
struct
(* Let's export SomeOrd into this functor for convenience *)
type t = SomeOrd.t
val compare = SomeOrd.compare
datatype tree = Leaf of t | Node of tree * t * tree
val singleton = Leaf
fun insert (x, Leaf) = Leaf x
| insert (x, Node (l, y, r)) =
case compare (x, y) of
GREATER => Node (l, y, insert (x, r))
| _ => Node (insert (x, l), y, r)
fun member (x, Leaf y) = compare (x, y) = EQUAL
| member (x, Node (l, y, r)) =
case compare (x, y) of
EQUAL => true
| LESS => member (x, l)
| GREATER => member (x, r)
end
可以像
一样使用structure IntBinTree = BinTree(struct
type t = int
val compare = Int.compare
end)
val myTree = IntBinTree.insert(5, IntBinTree.insert(3, IntBinTree.singleton 4))
这里的要点是在仿函数BinTree
中,所有函数都可以将订单比较运算符compare
视为理所当然,因此他们不必将它们作为参数传递。缺乏多态订单比较运算符和实现自定义重载的方法,我认为这两个选项是标准ML提供的最佳选择。
答案 1 :(得分:2)
我不确定你的函数应该做什么,因为除了名字之外它与mem
相同。
有两种方法:
如果您只有一个单独的函数,请将比较运算符作为参数。例如
fun qsort leq [] = []
| qsort leq [x] = [x]
| qsort leq (x::xs) =
let
val (ys, zs) = List.partition (fn y => leq (y, x)) xs
in
qsort leq ys @ [x] @ qsort leq zs
end
val l = qsort op<= [3, 4, 1, 9, 0]
如果您处理的不仅仅是几个函数,您可以使用仿函数来整体定义整个定义模块。