cha*_*ium 7 java scala higher-order-functions
我很难弄清楚如何从Scala高阶函数定义跳转到提供的示例.在幻灯片81上的幻灯片放映中提供了它.
这是高阶函数定义:
trait X[A] { def map[B](f: A => B): X[B] }
Run Code Online (Sandbox Code Playgroud)
这是提供的示例:
(1 to 10) map { x => x * 2 } // evaluates to Vector(2, 4, ..., 20)
(1 to 10) map { _ * 2 } // shorthand!
Run Code Online (Sandbox Code Playgroud)
咦?我不知道在这里有一些步骤.我得到的例子可能是利用函数定义和一些Scala细节.我只是没有足够的经验阅读Scala并做出连接假设.
我的背景是Java OO.我现在正在学习Scala和函数式编程.这不是第一个我不明白的例子.这只是第一个我觉得我有勇气发帖知道我会看起来无知的人.
我确实试过研究这个.首先,我去了Scala"圣经","Scala第二版编程",并尝试从那里了解是否存在(第165-9页).然后,我在StackOverflow上搜索了一下.我找到了几个围绕该地区的链接.但是,实际上并没有向我展示Scala高阶函数定义与提供的示例之间的连接,其方式是映射到此幻灯片中的特定实例.
这是我在StackOverflow上发现的:
我刚才意识到我跳过谷歌直接进入StackOverflow.嗯.如果你google并找到正确的链接,我很乐意看到它.我没有时间筛选使用像Monkey-monad,blastomorphisms等术语的所有谷歌链接,同时让我更加困惑,不太可能尝试解决这个问题.
高阶函数(或方法)是一种函数/方法,它既可以将函数作为参数,也可以将函数作为结果或两者.
在这种情况下,它是一个map
在列表,数组以及许多其他类型的容器之类的东西上定义的方法.当调用一个1 to 10
从1到10的数字范围时,由Range[Int]
Scala 表示,它逐个遍历它们并将该函数(作为参数传入的函数)应用于范围内的每个数字.此函数的结果将累积在一个新容器中 - Vector[Int]
在这种情况下,它将作为map
方法的结果返回.
那么(1 to 10) map { x => x * 2 }
btw语法糖(1 to 10).map(x => x * 2)
适用x => x * 2
于来自的数字1 to 10
.您可以将其视为回叫功能.你也可以像这样写:
(1 to 10).map( new Function1[Int, Int] {
override def apply(x: Int) = x * 2
})
Run Code Online (Sandbox Code Playgroud)
我认为以下只是为了显示Scala的一些集合属性而提供的示例签名.特别是它没有显示任何实现,因此您无法真正连接所有点.此外,它与实例并不一致......所以,这可能会令人困惑.
trait X[A] { def map[B](f: A => B): X[B] }
Run Code Online (Sandbox Code Playgroud)
我会把它读作:给定X
类型元素的集合类A
:
map
在类型上参数化的函数B
map
函数采用一个函数f
转换的单个A
到单个B
map
在类型X
的元素上返回相同类型的集合B
.然后它跳转到示例以说明使用:
(1 to 10) map { x => x * 2 }
Run Code Online (Sandbox Code Playgroud)
所以,连接点:
X
是(1到10)的类型,这里是aRange
f: A => B
是x => x * 2
推断为一个函数采取Int
和返回和Int
.Range
结束Int
,但这实际上会返回一个IndexedSeq
.一个更好的例子可能是:
List(1, 2, 3).map(i => i + "!") // a List[Int]
// returns a List[String]: List("1!", "2!", "3!")
Run Code Online (Sandbox Code Playgroud)
让我们用map方法定义一个数据类型,一个单链表.
sealed abstract class MyList[+A] {
def map[B](f: A => B): MyList[B] // higher order function declaration.
def head: A
def tail: MyList[A]
}
case class Cons[A](head: A, tail: MyList[A]) extends MyList[A] {
def map[B](f: A => B): MyList[B] = Cons[B](f(head), tail.map(f))
}
case object Nil extends MyList[Nothing] {
def map[B](f: Nothing => B): MyList[B] = this
def head = sys.error("head on empty list")
def tail = sys.error("tail on empty list")
}
Run Code Online (Sandbox Code Playgroud)
列表为空,或者是head
与列表的其余部分(the )配对的单个值(tail
).我们将两个案例表示为一个类层次结构,从密封的父类扩展MyList
.
注意执行Cons#map
,我们使用了f
两次参数,首先用它执行函数head
,然后传递给递归调用tail.map
.
语法f(head)
是简写f.apply(head)
,值f
是Function1
定义apply
方法的类的实例.
到现在为止还挺好.Let.s构建一个列表.
val list: MyList[Int] = Cons(1, Cons(2, Nil))
Run Code Online (Sandbox Code Playgroud)
现在,我们想通过转换每个元素将列表转换Ints
为新的String
s 列表.在Java中,您将明确地匿名子类Function1
,如下所示.
// longhand:
val stringList1: MyList[String] = list.map[String](new Function1[Int, String] {
def apply(a: Int): String = a.toString
})
Run Code Online (Sandbox Code Playgroud)
这在Scala中是合法的,但信噪比并不高.让我们使用匿名函数语法.
val stringList2: MyList[String] = list.map[String]((a: Int) => a.toString)
Run Code Online (Sandbox Code Playgroud)
我们可以进一步省略显式类型注释,其中编译器有足够的信息来推断它们.
首先,让我们a
根据元素类型推断出参数的类型list
.
val stringList3: MyList[String] = list.map[String](a => a.toString)
Run Code Online (Sandbox Code Playgroud)
这些非常简单的函数也可以用占位符语法表示.而不是声明参数,只需编写代码并_
用于任何未知数量.这样做,并允许stringList4
推断类型:
val stringList4 = list.map(_.toString)
Run Code Online (Sandbox Code Playgroud)