简体   繁体   English

Scala:理解参数多态性

[英]Scala: understanding parametric polymorphism

What is the difference between 有什么区别

def drop1[A](l: List[A]) = l.tail

and

def drop1(l: List[Int]) = l.tail

provided the usage looks something like 如果用法看起来像

drop1(List(1,2,3))

?

When should one or the other be used and why? 应该何时使用其中一个,为什么? Whereas I can understand the second example, I don't really understand the purpose of the first one. 虽然我能理解第二个例子,但我并不真正理解第一个例子的目的。

It's very simple really. 真的很简单。 Your first example refers to the concept of generics . 你的第一个例子是指泛型的概念。

Generics have a simple goal, to make certain methods generic , eg non-type dependant. 泛型有一个简单的目标,使某些方法通用 ,例如非类型依赖。

Lets look at this trivial example. 让我们看看这个简单的例子。 Say I want to write a drop1 method for List . 假设我想为List编写drop1方法。

I can either write one for every single type:(slow, repetitive): 我可以为每种类型写一个:(慢,重复):

def drop1(l: List[Int]): List[Int] = l.tail // this only works for Int

def drop1(l: List[String]): List[String] = l.tail // this only works for String 

You can see how you'd have to write the above for every single type. 您可以看到如何为每种类型编写上述内容。 To overcome this, you have generics: 为了克服这个问题,你有一些泛型:

def drop1[A](l: List[A]): List[A] = l.tail // this works for any given type.

Which essentially says: Whatever the type contained in the List is, give me the tail. 基本上说:无论List中包含什么类型,给我尾巴。 Instead of writing thousands of variants of drop1 for the virtually infinite number of types, I only need to write one. 而不是为几乎无限数量的类型编写成千上万的drop1变体,我只需要编写一个。

Now in Scala, your implementation is best done with: 现在在Scala中,您的实现最好用以下方法完成:

implicit class ListOps[A](val l: List[A]) extends AnyVal {
   def drop1: List[A] = l match {
     case head :: tail => tail
     case Nil => Nil
   }
}
// you can now have
List(1, 2, 3).drop1

It is also generally a bad idea to rename well known library methods. 重命名众所周知的库方法通常也是一个坏主意。 A tail operation is unsafe and a drop is safe. tail操作不安全, drop是安全的。 All you are causing is confusion, since there is a default drop method. 所有你造成的都是混乱,因为有一个默认的drop方法。

List(1, 2, 3) drop 1

In short -- some operations do not depend on a specific type and can be abstracted. 简而言之 - 一些操作不依赖于特定类型并且可以被抽象。 Counting apples and counting oranges is essentially the same operation. 计算苹果和计算橙子基本上是相同的操作。 If you're going to reuse algorithm, it is way smarter to abstract some types away instead of writing 如果你要重用算法,那么抽象一些类型而不是写作更聪明

def countOranges(xs: List[Orange]) = { some code } 
def countApples(xs: List[Apple]) = { the very same code }

My be little late , if you have an idea about generics in Java then analogy can be made here:- 我迟到了,如果你对Java中的泛型有了一个想法,那么可以在这里进行类比: -

Java --> generic class's object can be passed in method argument. Java - >泛型类的对象可以在方法参数中传递。

class Test<T> {
    // An object of type T is declared
    T obj;
    Test(T obj) {  this.obj = obj;  }  // constructor
    // some other methods in class 
}

Test<String> testobj = new Test<String>();

public void function(testobj){ 
// do something with testobj 
}

Scala --> Same way generic parametric functions work in scala. Scala - >通用参数函数在scala中的工作方式相同。 Here, [A] defines the generic Type in scala 这里,[A]定义了scala中的泛型Type

def drop1[A](l: List[A]) = l.tail

usage of above function:- 使用上述功能: -

scala>drop1(List(1,2,3))   // output List(2, 3)
scala>drop1(List(1.0,2.0,3.0)) // output List(2.0, 3.0)
scala>drop1(List('a','b','c'))  // output List(b, c)

Explanation:- Just pass any type of List it works like a charm.The syntax is like below:- 说明: - 只需传递任何类型的List,它就像魅力一样。语法如下: -

def function[Type](param:Type):Type = {do something}
//snippet to explain scala parametric polymorphism

object MethodParametricPolymorphism {
  //parametric polymorphism is similar/same as of java generics
  def countOranges(oranges : List[Orange]) = oranges.size;
  def countApples(apples : List[Apple]) = apples.size
  //if algo is same then paramatric polymorphism can be used
  def count[A](items : List[A]) = items.size

  val oranges : List[Orange] =  List( new Orange(1.1))
  val apples : List[Apple] =  List( new Apple(2.1), new Apple(2.2))

  countOranges(oranges);
  countApples(apples);
  //using polymorphic typed method
  count(oranges);
  count(apples);

  case class Orange ( weight: Double)
  case class Apple ( weight: Double)
 }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM