Functional programming 是否可以创建一个;“通用”;标准ML中的函数?
我想创建一个函数Functional programming 是否可以创建一个;“通用”;标准ML中的函数?,functional-programming,sml,smlnj,ml,mosml,Functional Programming,Sml,Smlnj,Ml,Mosml,我想创建一个函数remove_duplicates,它接受任何类型的列表(例如可以是int列表或bool列表或int列表或任何列表),并返回相同的列表而不重复,这在标准ML中是否可行?是。通过使用参数多态性,这在SML中是可能的。您需要一个最通用类型的函数'a list->'a list,其中'a是一个类型变量(即范围超过类型的变量),可以读取为alpha 有关如何应用此功能的更多具体示例(可选fun之后的显式类型变量): fun'a id(x:'a):'a=x 这里我们有一个类型为'a->'
remove_duplicates
,它接受任何类型的列表
(例如可以是int列表
或bool列表
或int列表
或任何列表
),并返回相同的列表而不重复,这在标准ML中是否可行?是。通过使用参数多态性,这在SML中是可能的。您需要一个最通用类型的函数'a list->'a list
,其中'a
是一个类型变量(即范围超过类型的变量),可以读取为alpha
有关如何应用此功能的更多具体示例(可选fun
之后的显式类型变量):
fun'a id(x:'a):'a=x
这里我们有一个类型为'a->'a
的标识函数
例如,我们可以声明具有某种类型专门化程度的类似函数
趣味地图[]=[]
|映射f(x::xs)=fx::映射fxs
其中,map
具有最通用的类型('a->'b)->'a list->'b list
,即,获取两个常用参数,一个具有某种函数类型,另一个具有某种列表类型(与函数的域一致),并返回一个具有函数的代码域给定类型的新列表
对于您的特定问题,您可能还希望使用相等函数来确定什么是“重复”,或者您可能将自己限制为“相等类型”(可以与op=
进行比较的类型,由带有两个前导撇号的类型变量表示,例如,''a
)是的,sml提供了多态性来做这些事情。在许多情况下,您实际上并不关心列表(或其他结构)中项目的类型。例如,此函数检查(已存在于列表
结构中)列表中是否存在项:
fun存在[]=false
|存在x(y::l)=x=y或存在x l
该函数适用于任何类型的列表,只要为该类型定义了相等运算符(该类型称为相等类型)。您可以对删除重复项执行相同的操作。为了处理非相等类型的项目列表,您必须为remove_duplicates
提供一个附加函数,用于检查两个项目是否相等
在标准ML中,是否有一个函数可以接受任何类型的列表并返回没有重复项的列表
没有
要确定一个元素是否与另一个元素重复,它们的值必须具有可比性。“任何类型”或标准ML中的'a
,在平等性方面不具有可比性。因此,虽然您不能有一个删除重复项的val nub:“列表->”列表,但这里有四个可选选项:
@qouify建议,内置的相等类型''a
,因此您可以在以下方面使用=
:
val nub : ''a list -> ''a list
@kopecs建议,一个以等式运算符作为参数的函数:
val nub : ('a * 'a -> bool) -> 'a list -> 'a list
这是1的概括,因为这里,nub op=:“一个列表->”一个列表
。这个解决方案有点简洁,因为它不仅可以删除重复项,还可以删除任意等价类的冗余表示,例如,nub(fn(x,y)=>(x mod 3)=(y mod 3))
将只保留不同模3的整数。但其复杂性为O(n²)。(-_- )ノ⌒┻━┻
因为它是O(n²)
文章还建议,另一种方法是使用排序而不是相等来将复杂性降低到O(n logn)。而在Haskell中,这意味着仅更改类型类约束:
nub :: Eq a => [a] -> [a]
nubOrd :: Ord a => [a] -> [a]
通过调整算法,在SML中表达这个约束会变得稍微复杂一些。虽然我们确实有''a
来表示Eq a=>a
(我们可以在输入上使用=
),但我们没有类似的特殊语法支持,可以比较为less/equal/greater,我们也没有类型类。我们有以下内置订单类型:
datatype order = LESS | EQUAL | GREATER
因此,如果您喜欢kopecs的解决方案,一个运行时间更好的变体是:
val nubOrd : ('a * 'a -> order) -> 'a list -> 'a list
因为它可以使用类似于先前看到的元素的数学集合,使用某种平衡搜索树实现;n插入每个复杂度O(logn)总共需要O(n logn)个步骤
SML的赢家特色之一是其可组合模块系统。您可以创建一个将另一个模块作为参数(函子)的模块,而不是使用参数多态性并向函数nubOrd
提供顺序比较函数
首先,让我们为表示类型排序的模块定义一个签名:
signature ORD =
sig
type t
val compare : t * t -> order
end
(请注意,t
前面没有一个”
)
这意味着任何人都可以制作结构。。。结束:通过为t
指定t
和相应的compare
函数,ORD
。许多内置类型具有预定义的compare
函数:int具有int.compare
和real具有real.compare
然后,定义一个基于树的集合数据结构;我使用了二进制搜索树,我跳过了大多数函数,但这些函数是执行这一壮举所必需的。理想情况下,您可以扩展接口并使用更好的树类型,例如自平衡树。(不幸的是,由于您已将此Q&A标记为SML/NJ和Moscow ML,我不确定要使用哪个模块,因为它们在平衡树方面以不同的方式扩展了标准库。)
最后,ListUtils
functor包含nubOrd
实用函数。函子采用结构X:ORD
,就像TreeSet
函子一样。它通过使用相同的排序模块专门化TreeSet
函子来创建XSet
结构。它是
functor TreeSet (X : ORD) =
struct
type t = X.t
datatype 'a tree = Leaf | Branch of 'a tree * 'a * 'a tree
val empty = Leaf
fun member (x, Leaf) = false
| member (x, Branch (left, y, right)) =
case X.compare (x, y) of
EQUAL => true
| LESS => member (x, left)
| GREATER => member (x, right)
fun insert (x, Leaf) = Branch (Leaf, x, Leaf)
| insert (x, Branch (left, y, right)) =
case X.compare (x, y) of
EQUAL => Branch (left, y, right)
| LESS => Branch (insert (x, left), y, right)
| GREATER => Branch (left, y, insert (x, right))
end
functor ListUtils (X : ORD) =
struct
structure XSet = TreeSet(X)
fun nubOrd (xs : X.t list) =
let
val init = ([], XSet.empty)
fun go (x, (ys, seen)) =
if XSet.member (x, seen)
then (ys, seen)
else (x::ys, XSet.insert (x, seen))
in rev (#1 (foldl go init xs))
end
end
structure IntListUtils = ListUtils(struct
type t = int
val compare = Int.compare
end)
val example = IntListUtils.nubOrd [1,1,2,1,3,1,2,1,3,3,2,1,4,3,2,1,5,4,3,2,1]
(* [1, 2, 3, 4, 5] *)
fun listCompare _ ([], []) = EQUAL (* empty lists are equal *)
| listCompare _ ([], ys) = LESS (* empty is always smaller than non-empty *)
| listCompare _ (xs, []) = GREATER (* empty is always smaller than non-empty *)
| listCompare compare (x::xs, y::ys) =
case compare (x, y) of
EQUAL => listCompare compare (xs, ys)
| LESS => LESS
| GREATER => GREATER
structure IntListListUtils = ListUtils(struct
type t = int list
val compare = listCompare Int.compare
end)
val example2 = IntListListUtils.nubOrd [[1,2,3],[1,2,3,2],[1,2,3]]
(* [[1,2,3],[1,2,3,2]] *)