数学基础
- 线性代数
- 概率论与随机过程
- 数值计算
- 蒙特卡洛方法与 MCMC 采样
- 机器学习方法概论
统计学习
深度学习
- 深度学习简介
- 深度前馈网络
- 反向传播算法
- 正则化
- 深度学习中的最优化问题
- 卷积神经网络
- CNN:图像分类
- 循环神经网络 RNN
- Transformer
- 一、Transformer [2017]
- 二、Universal Transformer [2018]
- 三、Transformer-XL [2019]
- 四、GPT1 [2018]
- 五、GPT2 [2019]
- 六、GPT3 [2020]
- 七、OPT [2022]
- 八、BERT [2018]
- 九、XLNet [2019]
- 十、RoBERTa [2019]
- 十一、ERNIE 1.0 [2019]
- 十二、ERNIE 2.0 [2019]
- 十三、ERNIE 3.0 [2021]
- 十四、ERNIE-Huawei [2019]
- 十五、MT-DNN [2019]
- 十六、BART [2019]
- 十七、mBART [2020]
- 十八、SpanBERT [2019]
- 十九、ALBERT [2019]
- 二十、UniLM [2019]
- 二十一、MASS [2019]
- 二十二、MacBERT [2019]
- 二十三、Fine-Tuning Language Models from Human Preferences [2019]
- 二十四 Learning to summarize from human feedback [2020]
- 二十五、InstructGPT [2022]
- 二十六、T5 [2020]
- 二十七、mT5 [2020]
- 二十八、ExT5 [2021]
- 二十九、Muppet [2021]
- 三十、Self-Attention with Relative Position Representations [2018]
- 三十一、USE [2018]
- 三十二、Sentence-BERT [2019]
- 三十三、SimCSE [2021]
- 三十四、BERT-Flow [2020]
- 三十五、BERT-Whitening [2021]
- 三十六、Comparing the Geometry of BERT, ELMo, and GPT-2 Embeddings [2019]
- 三十七、CERT [2020]
- 三十八、DeCLUTR [2020]
- 三十九、CLEAR [2020]
- 四十、ConSERT [2021]
- 四十一、Sentence-T5 [2021]
- 四十二、ULMFiT [2018]
- 四十三、Scaling Laws for Neural Language Models [2020]
- 四十四、Chinchilla [2022]
- 四十七、GLM-130B [2022]
- 四十八、GPT-NeoX-20B [2022]
- 四十九、Bloom [2022]
- 五十、PaLM [2022] (粗读)
- 五十一、PaLM2 [2023](粗读)
- 五十二、Self-Instruct [2022]
- 句子向量
- 词向量
- 传统CTR 预估模型
- CTR 预估模型
- 一、DSSM [2013]
- 二、FNN [2016]
- 三、PNN [2016]
- 四、DeepCrossing [2016]
- 五、Wide 和 Deep [2016]
- 六、DCN [2017]
- 七、DeepFM [2017]
- 八、NFM [2017]
- 九、AFM [2017]
- 十、xDeepFM [2018]
- 十一、ESMM [2018]
- 十二、DIN [2017]
- 十三、DIEN [2019]
- 十四、DSIN [2019]
- 十五、DICM [2017]
- 十六、DeepMCP [2019]
- 十七、MIMN [2019]
- 十八、DMR [2020]
- 十九、MiNet [2020]
- 二十、DSTN [2019]
- 二十一、BST [2019]
- 二十二、SIM [2020]
- 二十三、ESM2 [2019]
- 二十四、MV-DNN [2015]
- 二十五、CAN [2020]
- 二十六、AutoInt [2018]
- 二十七、Fi-GNN [2019]
- 二十八、FwFM [2018]
- 二十九、FM2 [2021]
- 三十、FiBiNET [2019]
- 三十一、AutoFIS [2020]
- 三十三、AFN [2020]
- 三十四、FGCNN [2019]
- 三十五、AutoCross [2019]
- 三十六、InterHAt [2020]
- 三十七、xDeepInt [2023]
- 三十九、AutoDis [2021]
- 四十、MDE [2020]
- 四十一、NIS [2020]
- 四十二、AutoEmb [2020]
- 四十三、AutoDim [2021]
- 四十四、PEP [2021]
- 四十五、DeepLight [2021]
- 图的表达
- 一、DeepWalk [2014]
- 二、LINE [2015]
- 三、GraRep [2015]
- 四、TADW [2015]
- 五、DNGR [2016]
- 六、Node2Vec [2016]
- 七、WALKLETS [2016]
- 八、SDNE [2016]
- 九、CANE [2017]
- 十、EOE [2017]
- 十一、metapath2vec [2017]
- 十二、GraphGAN [2018]
- 十三、struc2vec [2017]
- 十四、GraphWave [2018]
- 十五、NetMF [2017]
- 十六、NetSMF [2019]
- 十七、PTE [2015]
- 十八、HNE [2015]
- 十九、AANE [2017]
- 二十、LANE [2017]
- 二十一、MVE [2017]
- 二十二、PMNE [2017]
- 二十三、ANRL [2018]
- 二十四、DANE [2018]
- 二十五、HERec [2018]
- 二十六、GATNE [2019]
- 二十七、MNE [2018]
- 二十八、MVN2VEC [2018]
- 二十九、SNE [2018]
- 三十、ProNE [2019]
- Graph Embedding 综述
- 图神经网络
- 一、GNN [2009]
- 二、Spectral Networks 和 Deep Locally Connected Networks [2013]
- 三、Fast Localized Spectral Filtering On Graph [2016]
- 四、GCN [2016]
- 五、神经图指纹 [2015]
- 六、GGS-NN [2016]
- 七、PATCHY-SAN [2016]
- 八、GraphSAGE [2017]
- 九、GAT [2017]
- 十、R-GCN [2017]
- 十一、 AGCN [2018]
- 十二、FastGCN [2018]
- 十三、PinSage [2018]
- 十四、GCMC [2017]
- 十五、JK-Net [2018]
- 十六、PPNP [2018]
- 十七、VRGCN [2017]
- 十八、ClusterGCN [2019]
- 十九、LDS-GNN [2019]
- 二十、DIAL-GNN [2019]
- 二十一、HAN [2019]
- 二十二、HetGNN [2019]
- 二十三、HGT [2020]
- 二十四、GPT-GNN [2020]
- 二十五、Geom-GCN [2020]
- 二十六、Graph Network [2018]
- 二十七、GIN [2019]
- 二十八、MPNN [2017]
- 二十九、UniMP [2020]
- 三十、Correct and Smooth [2020]
- 三十一、LGCN [2018]
- 三十二、DGCNN [2018]
- 三十三、AS-GCN
- 三十四、DGI [2018]
- 三十五、DIFFPOLL [2018]
- 三十六、DCNN [2016]
- 三十七、IN [2016]
- 图神经网络 2
- 图神经网络 3
- 推荐算法(传统方法)
- 一、Tapestry [1992]
- 二、GroupLens [1994]
- 三、ItemBased CF [2001]
- 四、Amazon I-2-I CF [2003]
- 五、Slope One Rating-Based CF [2005]
- 六、Bipartite Network Projection [2007]
- 七、Implicit Feedback CF [2008]
- 八、PMF [2008]
- 九、SVD++ [2008]
- 十、MMMF 扩展 [2008]
- 十一、OCCF [2008]
- 十二、BPR [2009]
- 十三、MF for RS [2009]
- 十四、 Netflix BellKor Solution [2009]
- 推荐算法(神经网络方法 1)
- 一、MIND [2019](用于召回)
- 二、DNN For YouTube [2016]
- 三、Recommending What Video to Watch Next [2019]
- 四、ESAM [2020]
- 五、Facebook Embedding Based Retrieval [2020](用于检索)
- 六、Airbnb Search Ranking [2018]
- 七、MOBIUS [2019](用于召回)
- 八、TDM [2018](用于检索)
- 九、DR [2020](用于检索)
- 十、JTM [2019](用于检索)
- 十一、Pinterest Recommender System [2017]
- 十二、DLRM [2019]
- 十三、Applying Deep Learning To Airbnb Search [2018]
- 十四、Improving Deep Learning For Airbnb Search [2020]
- 十五、HOP-Rec [2018]
- 十六、NCF [2017]
- 十七、NGCF [2019]
- 十八、LightGCN [2020]
- 十九、Sampling-Bias-Corrected Neural Modeling [2019](检索)
- 二十、EGES [2018](Matching 阶段)
- 二十一、SDM [2019](Matching 阶段)
- 二十二、COLD [2020 ] (Pre-Ranking 模型)
- 二十三、ComiRec [2020](https://www.wenjiangs.com/doc/0b4e1736-ac78)
- 二十四、EdgeRec [2020]
- 二十五、DPSR [2020](检索)
- 二十六、PDN [2021](mathcing)
- 二十七、时空周期兴趣学习网络ST-PIL [2021]
- 推荐算法之序列推荐
- 一、FPMC [2010]
- 二、GRU4Rec [2015]
- 三、HRM [2015]
- 四、DREAM [2016]
- 五、Improved GRU4Rec [2016]
- 六、NARM [2017]
- 七、HRNN [2017]
- 八、RRN [2017]
- 九、Caser [2018]
- 十、p-RNN [2016]
- 十一、GRU4Rec Top-k Gains [2018]
- 十二、SASRec [2018]
- 十三、RUM [2018]
- 十四、SHAN [2018]
- 十五、Phased LSTM [2016]
- 十六、Time-LSTM [2017]
- 十七、STAMP [2018]
- 十八、Latent Cross [2018]
- 十九、CSRM [2019]
- 二十、SR-GNN [2019]
- 二十一、GC-SAN [2019]
- 二十二、BERT4Rec [2019]
- 二十三、MCPRN [2019]
- 二十四、RepeatNet [2019]
- 二十五、LINet(2019)
- 二十六、NextItNet [2019]
- 二十七、GCE-GNN [2020]
- 二十八、LESSR [2020]
- 二十九、HyperRec [2020]
- 三十、DHCN [2021]
- 三十一、TiSASRec [2020]
- 推荐算法(综述)
- 多任务学习
- 系统架构
- 实践方法论
- 深度强化学习 1
- 自动代码生成
工具
- CRF
- lightgbm
- xgboost
- scikit-learn
- spark
- numpy
- matplotlib
- pandas
- huggingface_transformer
- 一、Tokenizer
- 二、Datasets
- 三、Model
- 四、Trainer
- 五、Evaluator
- 六、Pipeline
- 七、Accelerate
- 八、Autoclass
- 九、应用
- 十、Gradio
Scala
- 环境搭建
- 基础知识
- 函数
- 类
- 样例类和模式匹配
- 测试和注解
- 集合 collection(一)
- 集合collection(二)
- 集成 Java
- 并发
二、模式匹配
模式匹配由
match
表达式实现,其语法为:xxxxxxxxxx
选择器 match { 可选分支一 可选分支二 ... }选择器
是一个表达式,match
将对该表达式的结果进行选择。可选分支
是以case
关键字打头的、包含一个模式以及一个或者多个表达式。- 模式和表达式通过箭头符
=>
分开。 - 如果匹配到该模式,则这些表达式就会被求值,求值结果将作为
match
表达式整体的结果。 - 如果没有表达式,则结果是
unit
值,即()
。
- 模式和表达式通过箭头符
一个
match
表达式的求值过程是按照给出的模式顺序逐一尝试的。- 一旦某个模式被匹配,则该模式后面跟着的表达式被执行。
- 一旦某个模式被匹配,则后续的模式将不再尝试。
match
和Java
的switch
很相似。但是它们有重要区别:xxxxxxxxxx
switch(选择器) { 可选分支一 可选分支二 ... }Scala
的match
是一个表达式,它总会返回一个值。Scala
的可选分支并不会贯穿到下一个case
。如果没有任何一个模式匹配上,则
Scala
会抛出MatchError
异常。这意味着你需要确保所有的
case
都会被覆盖到。
如果没有任何一个模式匹配上,此时你可以为选择器部分添加一个
@unchecked
注解。那么编译器对后续模式分支的覆盖完整性检查就会被抑制,这样就不会抛出MatchError
异常。xxxxxxxxxx
(选择器 : @unchecked) match { 可选分支一 可选分支二 ... }
2.1 模式种类
所有的模式跟相应的表达式看上去完全一样。
模式会按照代码中的顺序逐个被尝试。通常要求捕获通用的
case
出现在更具体的case
之后。如果我们将顺序颠倒过来,那么捕获通用的
case
就会在更具体的规则之前执行。在许多场景下,编译器甚至会拒绝编译。
2.1.1 通配模式
通配符
_
可以匹配任何对象。它常用于缺省的、捕获所有剩余可选路径。
xxxxxxxxxx
def f(expr : String) = expr match{ case "name" => println("catch:"+expr) case _ => println("default") // 默认 case }也可以用于忽略某个对象中你并不关心的局部信息。
xxxxxxxxxx
abstract class Parent case class C(name:String,age:Int) extends Parent def f(p: Parent) = p match{ case C(_,_) => println("catch:"+p) // 不关心 C 的参数 case _ => println("default") // 默认 case }
2.1.2 常量模式
常量模式仅仅匹配自己:
- 任何字面量都可以作为常量模式使用。如:
"+"
和1
这样的常量模式可以匹配那些按照==
的要求跟它们相等的值。 - 任何
val
或单例对象也可以被当作常量模式使用。如:Nil
这个单例对象仅能匹配空列表。
xxxxxxxxxx
val S = "world" def f(x:Any) = x match{ case 1 => "catch:1" case "hello" => "catch:hello" case Nil => "catch:empty list" // 单例对象作为常量模式 case S => "catch:"+S // val 作为常量模式 case _ => "default" }- 任何字面量都可以作为常量模式使用。如:
2.1.3 变量模式
类似
e
这样的变量模式可以匹配任何值。匹配后,在右侧的表达式中,这个变量e
将绑定成该匹配的值。在绑定之后,你可以用这个变量来做进一步处理。
xxxxxxxxxx
def f(x:Any) = x match{ case e => println(e) }通配符模式
_
也可以匹配任何值,但是它并不会引入一个变量名来指向这个值。采用变量模式之后,就没必要继续跟着通配符模式
_
。因为变量模式已经可以匹配任何值了,因此不可能走到后面的case
。常量模式中,也有可能出现符号形式的名字,如
Nil
。当我们将Nil
当作一个模式的时候,实际上就是在用一个符号名称来引用常量。Scala
通过一个简单的词法规则来区分:以一个小写字母打头的简单名称会被当作模式变量处理。
所有其它引用都是常量。
如果需要用小写的名称作为模式常量,有两个办法:
如果常量是某个对象的字段,则可以在字段名之前加上限定词。如
this.n
。尽管它们是以小写开头,但是由于
.
的存在,它们会被解析为常量模式。使用反引号将这个名字包围起来。
Scala
中反引号有两个用途:- 将小写字母打头的标识符用作模式匹配中的常量。
- 将关键字当作普通的标识符。
xxxxxxxxxx
val name = "hello" def f(x:Any) = x match{ case `name` => println("catch hello") case Nil => println("catch Nil") case nil => println("catch:"+nil) } f("hello") // 匹配到 name: 常量模式 f(List()) // 匹配到 Nil :常量模式 f("world") // 匹配到 nil :变量模式
2.1.4 构造方法模式
构造方法模式看上去就像
UnOP("_",e)
。这个模式匹配所有类型为UnOP
,并且首个入参匹配"_"
、第二个入参匹配e
的值。构造方法模式由一个名称和一组圆括号中的模式组成。假设这里的名称是一个样例类,则这样的一个模式:
首先检查被匹配的对象是否是以这个名称命名的样例类的实例。
然后检查这个对象的构造方法参数是否匹配这些额外给出的模式。
- 这些额外的模式意味着
Scala
的模式支持深度匹配。这样的模式不仅检查给定的对象的顶层,还将进一步检查对象的内容是否匹配额外的模式要求。 - 由于额外的模式也可能是构造方法模式,因此检查对象内部时可以到任意的深度。
- 额外的模式可以通过通配符
_
或者其它的模式来匹配。尤其可以通过变量模式来绑定匹配的值。
- 这些额外的模式意味着
xxxxxxxxxx
case class Worker(name:String,life_time:Double) case class System(worker:Worker,lift_time:Double) def f(x:Any) = x match{ case System(Worker(name,10.0),t) => println("a:worker name="+ name + " ; system life="+t) case System(Worker(name,_),t) => println("b:worker name="+ name + " ; system life="+t) case other => println("catch other: "+other) } f(System(Worker("first",10.0),100.0)) // 匹配到第一个 case f(System(Worker("second",11.0),100.0)) // 匹配到第二个 case f(Worker("second",11.0)) // 匹配到第三个 case
2.1.5 序列模式
和样例类匹配一样,也可以和序列类型做匹配,如
List
或Array
,使用的语法是相同的。可以在模式中给出任意数量的元素。
如果想匹配一个序列,但又不想给出很长的元素,则可以用
*_
作为模式的最后一个元素。这种方式可以匹配序列中任意数量的元素,包括
0
个元素。
xxxxxxxxxx
def f(x:Any) = x match { case List(0,_) => println("2 elements list,start with 0") case List(0,_,_) => println("3 elements list,start with 0") case List(e,_,_,_) => println("4 elements list,catch :"+e) // 绑定到 e case List(0,_*) => println("various elements list,start with 0") // 以 0 开始的任意长度 case _ => println("default") } f(List(0)) // case List(0,_*) f(List(0,1)) // case List(0,_) f(List(0,1,2)) // case List(0,_,_) f(List(0,1,2,3)) // case List(e,_,_,_) : e 为 0 f(List(0,1,2,3,4)) // case List(0,_*) f(Array(0,1)) // case _
2.1.6 元组模式
模式匹配还支持元组。形如
(a,b,c)
这样的模式能够匹配任意的三元组。xxxxxxxxxx
def f(x:Any) = x match { case (a,b,c) => println("a:"+a+" ;b:"+b+" ;c:"+c) case _ => println("default") } f(1,"second",3.0) // case (a,b,c)
2.1.7 带类型的模式
可以用带类型的模式来替换类型测试和类型转换。
假如需要设计一个函数,该函数返回不同类型的对象的大小或者长度。常规的设计思路时:通过类型测试以及类型转换:
xxxxxxxxxx
def get_size(x:Any) = { if x.isInstanceOf[String]{ // 如果是字符串 val s = x.asInstanceOf[String] // 强制类型转换 s.length }else ... // 如果是其它序列,如 List,Map 等 }通过
expr.isInstanceOf[T]
可以判断expr
是否是T
类型,通过expr.asInstanceOf[T]
可以将expr
转换成T
类型。这两个操作符会被当成
Any
类的预定义方法处理,它们接收一个用方括号括起来的类型参数。Scala
中编写类型测试和类型检查会很罗嗦。这是有意为之,因为Scala
并不鼓励这样做。Scala
推荐使用带类型的模式,尤其是当你需要同时执行类型测试和类型转换时。因为这两个操作所作的事情会被并在单个模式匹配中完成。xxxxxxxxxx
def get_size(x:Any) = x match { case s: String => s.length case m: Map[_,_] => m.size case _ => -1 }
在类型模式中,你也可以使用下划线来通配任意类型,这就像是其它模式中的通配符。如
Map[_,_]
。和
Java
一样,Scala
的泛型采取了类型擦除。这意味着运行时并不会保留类型参数的信息。因此我们在运行时无法判断某个给定的Map
对象是由两个Int
的类型参数创建,还是由其它类型参数创建。系统只能判断某个对象是不是Map
。对这个规则唯一例外的是数组。因为
Java
和Scala
都对它们进行了特殊处理,数组的元素类型和数组是一起保存的,因此可以对其进行模式匹配。xxxxxxxxxx
def isIntIntMap(x:Any) = x match{ case m: Map[Int,Int] => true case _ => false } def isIntArray(x:Any) = x match{ case a: Array[Int] => true case _ => false } println(isIntIntMap(Map[Int,Int](100 -> 1, 200 ->2))) // 输出: true println(isIntIntMap(Map[String,Int]("a" -> 1,"b"->2))) // 输出: true println(isIntArray(Array[Int](1,2,3))) // 输出: true println(isIntArray(Array[String]("a","b","c"))) // 输出: false
2.2 变量绑定
除了独立存在的变量模式之外,还可以对任何其它模式添加变量。方式为:
变量名@模式
,这就得到一个变量绑定模式。变量绑定模式和常规模式一样执行模式匹配。如果匹配成功,就将匹配的对象赋值给这个变量,就像简单的变量模式一样。
xxxxxxxxxx
case class Worker(name:String,life_time:Double) case class System(worker:Worker,lift_time:Double) def f(x:Any) = x match{ case System(worker@Worker(_,_),t) => println("worker:"+ worker) // 绑定到 worker case other => println("catch other: "+other) } f(System(Worker("first",10.0),100.0))
2.3 模式守卫
Scala
要求模式都是线性的:同一个模式变量在模式中只能出现一次。xxxxxxxxxx
case class Worker(name:String,life_time:Double) case class System(worker:Worker,lift_time:Double) def f(x:Any) = x match{ case System(worker@Worker(_,t),t) => println(worker) // 希望两个 lift_time 是一样的,但是这里会编译失败 case other => println("catch other: "+other) }如果希望模式变量出现多次,则可以用模式守卫来重新定义匹配逻辑。模式守卫出现在模式之后,并以
if
打头。- 模式守卫可以是任意的布尔表达式,通常会引用到模式中的变量。
- 如果存在模式守卫,则这个匹配仅在模式守卫求值得到
true
时才会成功。
xxxxxxxxxx
case class Worker(name:String,life_time:Double) case class System(worker:Worker,lift_time:Double) def f(x:Any) = x match{ case System(worker@Worker(_,t1),t2) if t1==t2 => println("worker:"+ worker) // 模式守卫 case other => println("catch other: "+other) } f(System(Worker("first",10.0),10.0)) // 匹配到第一个 case f(System(Worker("second",10.0),20.0)) // 匹配到第二个 case
2.4 密封类
当我们编写一个模式匹配时,需要确保完整地覆盖了所有可能的
case
。有时候可以通过在末尾添加一个缺省
case
来做到,但是这仅限于有合理兜底的场景。如果没有一个缺省的
case
,我们可以求助于Scala
编译器,编译器帮我们检测出match
表达式中缺失的模式组合。为了做到这一点,编译器需要分辨出所有可能的
case
有哪些。事实上这是不可能的。
xxxxxxxxxx
def f(x:Any) = x match{ case i:Int => println("catch int:"+i) case s:String => println("catch String:"+s) /* 如果没有缺省 case,Scala 很难知道所有可能的 case 有哪些 */ }解决这个问题的方法是:将这些样例类的超类标记为密封的。语法是:在类继承关系顶部的那个类的类名前加上
sealed
关键字。密封类除了在同一个文件中定义的子类之外,不能添加新的子类。这对于模式匹配而言非常有用,因此我们就只需要关心那些已知的样例类。
此外编译器还能更好的支持模式匹配。如果对继承自密封类的样例类进行匹配,编译器会用警告消息标识出缺失的模式组合。
因此如果你的类打算被用于模式匹配,则你应该将其作为密封类。这也是为什么
sealed
关键字通常被看作模式匹配的通行证的原因。xxxxxxxxxx
sealed abstract class Man case class Worker(name:String) extends Man case class Leader(name:String) extends Man def f(x:Man) = x match{ case w:Worker => println("catch worker:" + w) } f(Worker("worker_1")) /* 编译器警告: Warning:(5, 24) match may not be exhaustive. It would fail on the following input: Leader(_) def f(x:Man) = x match{ */解决办法是:添加一个缺省的
case
用于捕获所有的模式,或者补全缺失的样例类。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论