我在函数中读到了多态性并看到了这个例子
fun len nil = 0
| len rest = 1 + len (tl rest)
所有其他例子也涉及nil
arg。
我想检查其他类型的多态性概念,比如
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)
上述功能有什么错误?它完全合法吗?
答案 0 :(得分:2)
子类型多态性:
在Java,C#o C ++等编程语言中,您有一组管理多态的子类型规则。例如,在面向对象的编程语言中,如果你的类型A是类型B的超类型;然后,无论A出现在哪里,你都可以通过B,对吧?
例如,如果您有哺乳动物类型,而狗和猫是哺乳动物的亚型,那么无论在哪里出现哺乳动物,您都可以通过狗或猫。
您可以使用数据类型和构造函数在SML中实现相同的概念。例如:
datatype mammal = Dog of String | Cat of String
然后,如果你有接受哺乳动物的功能,例如:
fun walk(m: mammal) = ...
然后你可以传递一只狗或一只猫,因为它们是哺乳动物的构造者。例如:
walk(Dog("Fido"));
walk(Cat("Zoe"));
因此,这就是SML在面向对象语言中实现类似于我们所知的子类型多态的方式。
Ad-hoc Polymorphysm:
的强制
实际的混淆点可能是Java,C#和C ++等语言通常具有类型的自动强制。例如,在Java中, int 可以自动强制转换为 long ,将 float 强制转换为 double 。因此,我可以有一个接受双打的函数,我可以传递整数。有些人称这些自动强制为ad-hoc多态。
SML中不存在这种形式的多态性。在这些情况下,您被迫手动强制或将一种类型转换为另一种类型。
fun calc(r: real) = r
你不能用整数来调用它,为此必须先转换它:
calc(Real.fromInt(10));
因此,正如您所看到的,SML中没有此类ad-hoc多态。您必须手动进行铸件/转换/强制。
功能重载
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"));
因此,正如您所看到的,结合所有这些不同形式的多态性,您应该能够实现与其他静态类型语言相同的操作。
答案 1 :(得分: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
wrapper
可以包含整数或字符串。