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]] *)