0

我阅读了函数中的多态性并看到了这个例子

 fun len nil = 0
   | len rest = 1 + len (tl rest)

所有其他示例也处理nilarg。

我想检查其他类型的多态性概念,例如

fun func (a : int) : int = 1  
  | func (b : string) : int = 2  ;

并得到以下错误

stdIn:1.6-2.33 Error: parameter or result constraints of clauses don't agree 
[tycon mismatch]
  this clause:      string -> int
  previous clauses:      int -> int
  in declaration:
    func = (fn a : int => 1: int
             | b : string => 2: int)

上述函数中的错误是什么?这完全合法吗?

4

2 回答 2

2

亚型多态性:

在 Java、C# 或 C++ 等编程语言中,您有一组控制多态性的子类型规则。例如,在面向对象的编程语言中,如果您的类型 A 是类型 B 的超类型;那么无论A出现在哪里,您都可以通过B,对吗?

例如,如果你有一个哺乳动物类型,而狗和猫是哺乳动物的子类型,那么无论哺乳动物出现在哪里,你都可以传递狗或猫。

您可以使用数据类型和构造函数在 SML 中实现相同的概念。例如:

datatype mammal = Dog of String | Cat of String

然后,如果您有一个接收哺乳动物的函数,例如:

fun walk(m: mammal) = ...

然后你可以传递 Dog 或 Cat,因为它们是哺乳动物的构造函数。例如:

walk(Dog("Fido"));
walk(Cat("Zoe"));

所以这就是 SML 实现类似于我们所知的面向对象语言中的子类型多态性的方式。

临时多态性:

强制

实际的混淆点可能是 Java、C# 和 C++ 等语言通常具有自动强制类型转换。例如,在 Java 中,int可以自动强制转换为longfloat可以自动强制转换为double。因此,我可以有一个接受双精度的函数,并且可以传递整数。有人将这些自动强制称为 ad-hoc 多态性。

这种形式的多态性在 SML 中不存在。在这些情况下,您被迫手动强制或将一种类型转换为另一种类型。

fun calc(r: real) = r

您不能使用整数调用它,为此您必须先转换它:

calc(Real.fromInt(10));

因此,如您所见,SML 中不存在这种特殊的多态性。您必须手动进行强制转换/转换/强制。

函数重载

另一种形式的 ad-hoc 多态性是我们在 Java、C# 和 C++ 等语言中所说的方法重载。同样,在 SML 中没有这样的东西。您可以定义两个不同名称的不同函数,但不能使用相同的函数(相同名称)接收不同的参数或参数类型。

不要将函数或方法重载的概念与您在示例中使用的概念混淆,后者只是函数的模式匹配。这是这样的合成糖:

fun len xs =
  if null xs then 0
  else 1 + len(tl xs)

参数多态性:

最后,SML 提供了参数多态性,这与泛型在 Java 和 C# 中所做的非常相似,我理解这有点类似于 C++ 中的模板。

所以,例如,你可以有一个像

datatype 'a list = Empty | Cons of 'a * 'a list

在这样的类型中,'a 代表任何类型。因此这是一种多态类型。因此,我可以使用相同的类型来定义整数列表或字符串列表:

val listOfString = Cons("Obi-wan", Empty);

或整数列表

val numbers = Cons(1, Empty);

或哺乳动物列表:

val pets = Cons(Cat("Milo", Cons(Dog("Bentley"), Empty)));

这与您可以对 SML 列表执行的操作相同,它也具有参数多态性:

您可以定义许多“不同类型”的列表:

val listOfString = "Yoda"::"Anakin"::"Luke"::[]
val listOfIntegers 1::2::3::4::[]
val listOfMammals = Cat("Misingo")::Dog("Fido")::Cat("Dexter")::Dog("Tank")::[]

在同样的意义上,我们可以在函数中有参数多态性,就像在下面的例子中我们有一个恒等函数:

fun id x = x

x 的类型是 'a,这基本上意味着您可以将其替换为您想要的任何类型,例如

id("hello");
id(35);
id(Dog("Diesel"));
id(Cat("Milo"));

因此,如您所见,结合所有这些不同形式的多态性,您应该能够实现您在其他静态类型语言中所做的相同事情。

于 2013-02-26T16:01:48.053 回答
1

不,这不合法。在 SML 中,每个函数都有一个类型。len您作为示例提供的函数类型是

fn : 'a list -> int

也就是说,它接受任何类型的列表并返回一个整数。您尝试创建的函数采用整数字符串,并返回一个整数,这在 SML 类型系统中是不合法的。通常的解决方法是制作一个包装器类型:

datatype wrapper = I of int | S of string

fun func (I a) = 1
  | func (S a) = 2

该函数具有类型

fn : wrapper -> int

wherewrapper可以包含整数或字符串。

于 2013-02-26T14:08:25.143 回答