• scala中的 Type Lambda


    先回顾以下几点:

    • scala的类型投影
    • 类型别名
    • scala中的函数柯里化

    scala的类型投影

    同java类似,scala中也存在内部类和外部类。
    但是与java的内部类不同的时,scala的内部类实例类型与其路径相关,比如

    class Outer {
      thisOuter =>
    
      class Inner {
        thisInner =>
        override def toString: String = s"[${thisOuter}].[${thisInner.hashCode()}]"
      }
    
      override def toString: String = s"[${thisOuter.hashCode()}]"
    }
    

    在以下代码中,如何描述i0i1的类型?

    val o0 = new Outer()
    val i0 = new o0.Inner()
    
    val o1 = new Outer()
    val i1 = new o1.Inner()
    

    对于i0的类型是o0.Inner,而i1的类型是o1.Inner,此时,将该形式的类型称为路径依赖类型

    在具体编程实践中,需要代码更加通用,不可以为每一个Inner实例都写一遍其具体的路径依赖类型,,于是就有了投影类型,关键字为#,使用方式为A#B,表示每一个类型A实例下的B类型,而不需要区分哪一个实例A。

    val o0 = new Outer()
    val i0: o0.Inner = new o0.Inner()
    val o1 = new Outer()
    val i1: o1.Inner = new o1.Inner()
    
    val i0_0: Outer#Inner = i0
    val i1_0: Outer#Inner = i1
    

    可以类比于从上海坐飞机、走铁路、走高速都可以去北京,也可以简洁的说从上海去北京仅此而已,不需要讲具体的方式。

    注意:以上所说的都是关于类型,而不是类。

    类型别名

    在scala中源码中,已经存在大量的类型别名的预定义,比如

    type String        = java.lang.String
    type Class[T]      = java.lang.Class[T]
    type Function[-A, +B] = Function1[A, B]
    type Map[A, +B] = immutable.Map[A, B]
    

    在编程实践中,可以使用类型别名来赋予一般类型业务含义。

    scala中的函数柯里化

    函数柯里化,作用是给函数传递一部分参数,使其返回新函数来处理剩下的参数

    使用豆子和水做成豆浆举例,豆子Bean和水Water两个参数,进过某些函数作用生成豆浆BeanMilk。原函数如下表示

    def makeBeanMilk1(b: Bean, w: Water): BeanMilk = {
        b.doSomeThingWith(w)
    }
    

    以上函数可以写成以下柯里化形式:

    def makeBeanMilk2(b: Bean)(w: Water): BeanMilk = {
      b.doSomeThingWith(w)
    }
    

    当函数makeBeanMilk2仅一个Bean参数时,可以得到新函数Water => BeanMilk,表示已经接收到了一个Bean参数,现在只缺一个Water参数。

    val makeBeanMilk2WithBean: Water => BeanMilk = makeBeanMilk2(Bean(1))
    

    以上的柯里化形式的函数makeBeanMilk2等价于

    def makeBeanMilk3: Bean => Water => BeanMilk = {
        b => w => b.doSomeThingWith(w)
    }
    

    Type Lambda

    Type Lambda以下简称为类型lambda,其作用简而言之为构造器类型参数的柯里化

    (x:Int)=>println(x)该语句的类型为Int=>Unit或者Function1[Int,Unit],其中设计到泛型参数为IntUnit

    以函子Functor举例,函子是对函数式编程中map转换函数的抽象。

    trait Functor[F[_]] {
      def map[A, B](fa: F[A])(fun: A => B): F[B]
    }
    

    以上代码,泛型参数F[_]表示类型F还有一个高阶类型参数,这里把F类比为Option、List、Set等,而这里的_用法与存在类型或者偏应用函数并不同,仅仅表示泛型参数F还有泛型参数。

    type F1 = Functor[Option]
    type F2 = Functor[List]
    

    以上可以编译,但是对于Map来说编译不通过

    type F3 = Functor[Map]
    //Map takes two type parameters, expected: one
    

    那么该如何解决呢?
    思路为将两个类型参数变为一个类型参数即可编译通过。

    解决:将Map类型再次声明一个新的类型,由两个泛型参数变为一个。

    type IntAMap[A] = Map[Int, A]
    type F3 = Functor[IntAMap]
    

    以上产生了一个不需要的新类型IntAMap,将其省略进而写为

    type F3 = Functor[({type IntAMap[A] = Map[Int, A]})#IntAMap]
    

    类型lambda与函数柯里化的相似点是,函数柯里化设置了部分参数后返回新函数,新函数只需要传入另一部分的参数。类型lambda设置了一部分的泛型参数,返回了只需要另外一部分泛型参数的构造器。

    注意{type IntAMap[A] = Map[Int, A]}的语法,使用大括号{}表明为结构类型,至于该结构类型的具体类型名称不需要关注,再使用#将其内部的类型别名投影出来。

    val instance = new {
        type AA = String
        val aa: AA = "sd"
        type T[A] = Map[Int, A]
    }
    
    知难行易
    原创博文,请勿转载
    我的又一个博客hangscer.win
  • 相关阅读:
    分布式框架---Dubbox 简介
    MySql 多表查询
    MySql 增删改查
    redis
    spring security 自定义登录页面及从数据库查询账户登录
    java数据结构-
    Maven-
    有关多行相同数据,只显示在第一行的实现
    javaWEB的第一次MVC之旅
    JavaWeb中的 请求转发 和 重定向
  • 原文地址:https://www.cnblogs.com/hangscer/p/13158253.html
Copyright © 2020-2023  润新知