具有不同参数类型的函数

时间:2013-02-26 11:54:26

标签: functional-programming sml smlnj

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

 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)

上述功能有什么错误?它完全合法吗?

2 个答案:

答案 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可以包含整数或字符串。