美文网首页
设计概要

设计概要

作者: pcz | 来源:发表于2017-09-21 21:33 被阅读0次

    设计概要

    注释

    // 注释
    /* 注释 */
    

    内置类型

    [bool, byte, char, short, int, unit]    // 值类型
    [String, List, Map]      // 对象
    

    变量定义

    var i: int = 0;
    
    // 列表
    var l: List<int> = [1, 2, 3, 4, 5];
    l[0] = 1;
    
    // 字典
    var m: Map<int->string> = {
      "a" -> 1,
      "b" -> 2
    }
    m["a"] = 1;
    
    // 函数
    var x: int => int = (p:int) => p
    

    函数定义

    def add(a:int,b:int):int = {
      return  a+b;
    }
    

    first class function

    def addx(x:int): int => int = {
       return (a:int) => x+a;
    }
    

    类定义

    class A extends B {
    public/private/protected:
      var a:int = 0;
      // 构造函数
      def A(a:int) = {
         this.a = a;
      }
      // 成员函数
      def s() = {
        print(this.a);
      }
    }
    

    接口

    这里的接口相当于java的interface,只不过在类外实现。

    • 最普通的接口
    interface showable
    {
      def show(this:This);
    }
    // 为非泛型类实现trait
    impl showable for int
    {
      def show(this:int) = {
        print(this);
      }
    }
    1.show() // 合法
    // 为泛型类实现trait
    template<A,B>
    class Pair{
    public:
      def Pair(a:A, b:B) = {
        this.a = a;
        this.b = b;
      }
      var a:A;
      var b:B;
    }
    
    // 全泛化
    template<A,B>
    impl showable for Pair<A,B>
    {
      def show(this) = {
        print(a,b);
      }
    }
    // 偏特化,带有泛型约束
    template<A,B>
    where A: extends Object impl Hash 
          B: extends Object impl Hash
    impl showable for Pair<A,B>  
    {
      def show(this:Pair<A,B>) = {
        print(a.hashCode(),b.hashCode());
      }
    }
    // 实体化
    impl showable for Pair<int,int>
    {
      def show(this:Pair<int,int>) = {
        print(a,b);
      }
    }
    
    • 泛型接口
      这里演示一个泛型接口的问题,即因为命名冲突,一个泛型接口无法被实现两次:
    template<T>
    interface Get
    {
      def get(this:This):T 
    }
    
    impl Get<int> for int {
      def get(this:int):int {
        return this;
      }
    }
    
    impl Get<String> for int {
      def get(this:int):String {
        return this.toString()
      }
    }
    1.get() // ambiguous, which one to choose?
    

    泛型接口的本质是要对接口规定方法的类型签名做出限制,但是确实存在如上的问题。

    怎么解决?去掉泛型接口。但是可以用concept来绕过。

    算了吧还是留着吧,反正java也这样。

    concept

    interface偏重扩展类的行为,而concept偏重约束类的特征。

    concept必须拥有类的完全访问权?这点还是待定吧,不一定有这样的需求吧。

    前面的例子:

    concept Get<T,Result>
    {
      def get(x:T):Result;
    }
    
    instance Get<int,int>
    {
      def get(x:int):int = {
        return x;
      }
    }
    
    instance Get<int,String>
    {
      def get(x:int):String = {
        return x.toString();
      }
    }
    
    Get<int,int>::get(1);    // 合法, = 1
    Get<int,String>::get(2); // 合法, = "2"
    

    完美解决。

    下面看一个更一般的例子,实现一个幺半群(有满足结合律的加法和单位元)。
    scala代码:

    abstract class SemiGroup[A] {
      def add(x: A, y: A): A
    }
    abstract class Monoid[A] extends SemiGroup[A] {
      def unit: A
    }
    object ImplicitTest extends App {
      implicit object StringMonoid extends Monoid[String] {
        def add(x: String, y: String): String = x concat y
        def unit: String = ""
      }
      implicit object IntMonoid extends Monoid[Int] {
        def add(x: Int, y: Int): Int = x + y
        def unit: Int = 0
      }
      def sum[A](xs: List[A])(implicit m: Monoid[A]): A =
        if (xs.isEmpty) m.unit
        else m.add(xs.head, sum(xs.tail))
    
      println(sum(List(1, 2, 3)))       // uses IntMonoid implicitly
      println(sum(List("a", "b", "c"))) // uses StringMonoid implicitly
    }
    

    Hint代码:

    template<A>
    concept SemiGroup {
      def add(x: A, y: A): A
    }
    
    template<A>
    concept Monoid combine SemiGroup
    {
      def unit():A;
    }
    
    instance SemiGroup<String> {
        def add(x: String, y: String): String = {
          return x+y;
       }
    }
    instance Monoid<String>{
      def unit():String {
        return "";
      }
    }
    
    instance SemiGroup<int> {
        def add(x: int, y: int): int = {
          return x+y;
       }
    }
    instance Monoid<int>{
      def unit():int{
        return 0;
      }
    }
    
    template<A>
    where A: instance Monoid<A>
    def sum(xs: List[A]): A = {
      if (xs.isEmpty) 
        // 这里的‘Monoid’是简写形式,允许你直接使用instance限制里出现的concept
        return Monoid::unit() 
    
      return Monoid::add(xs.head, sum(xs.tail)) 
    }
    

    可以发现二者的不同,concept偏向于短代码的组合,而没有继承链这一说。还有一个优势是,在你需要类型SemiGroup<int>这种形式的参数时,我们已经实现过它了。而目前并没有这样的隐式值。

    需要注意一点,如同类继承,concept不能有循环依赖。

    template <A>
    concept SemiGroup
    where a: instance SemiGroup // 错误!依赖自身!
    {
      def add(x: A, y: A): A
    }
    
    template <A>
    concept SemiGroup
    where a: instance Monoid<A> // 错误!循环依赖!
    {
      def add(x: A, y: A): A
    }
    
    template <A>
    concept Monoid
    where A: instance SemiGroup<A>
    {
      def unit():A;
    }
    

    解决方法是按声明顺序识别依赖关系,如果一个concept依赖另一个尚未声明的concept,直接报错即可。

    concept结合OO

    可以看到concept和泛型的abstract class功能好像是相似的,怎么解决这个问题?

    解决了,concept是对类型的限制,比如Monoid[A]表明类型A满足幺半群的公理,即类型本身满足公理。而class内部定义类的数据和行为。也就是一个是外部的限制,一个是自身的行为。

    template <Elem, Result, template F<_>>
    concept Functor {
      def fmap(x: Elem =>Result): F<Elem> => F<Result>   
    }
    
    // 偏特化
    template<Elem, Result>
    instance Functor<Elem, Result, List<Elem>> {
      override def fmap(func: Elem => Result): List<Elem> => List<Result> = {
        return list => list.map(func);
        // 做自动类型推导
        // 等价于 return (list:List<Elem>):List<Result> => list.map(func)
      }
    }
    
    // 偏特化
    template<Elem, Result>
    instance Functor<Elem, Result, Option<Elem>> {
      override def fmap(func: Elem => Result): Option<Elem> => Option<Result> = {
        return m => {
           return switch m {
             case null => null;
             case Some(e) => Some(func(e));
           }
        }
      }
    }
    
    // 于是
    var l:List<int> = [1,2,3,4];
    var f = Functor<int, String, List<int>>::fmap( x => x.toString());
    // 最好能够自动推导,写成
    var g = Functor::fmap( (x:int) => x.toString() )
    
    f(l); // 结果 = ["1","2","3","4"]
    
    

    想要用高阶类型不得不使用template语法。。。

    template <A,B,C>
    concept AddEq {
      def add(x:A,y:B):C
    }
    
    instance AddEq<int,int,int> {
      override def add(x:int,y:int):int = {
         return x+y;
      }
    }
    
    template <T>
    instance AddEq<T,T,String> {
      override def add(x:T,y:T):String = {
         return x.toString()
      }
    }
    
    template<T>
    def add(x:T,y:T)
    

    再考虑一个concept和高阶类型的区别:

    // 泛型类实现
    template<Elem>
    class Stack {
      var data:Array<T>;
      var pos:int;
      def Stack() {
        data = new Array<T>();
      }
      def pop(e:Elem) {    
        pos = pos - 1;   
      }
      def push(e:Elem) {
        data[pos] = e;
        pos = pos + 1;   
      }
      def top():Elem {
        return data[pos-1];
      }
    }
    

    linq (糖

    var l:List[int] = [-1,-2,0,1,2];
    from a in l
      from b in l
        from c in l
    where a > 0 && b>0 && c>0
    select (a,b,c);
    

    模式匹配 (糖

    // 注意switch是语句,不是表达式
    switch x {
      case 1 => xxx; // 不用break
      case a:string => xxx;
      case A(a,b) => xxx;
      default: xxx;
    }
    

    递归模板

    data List a = Nil | Cons a (List a)
    
    template <T>
    type List<T> = null | Cons<T, List<T> >
    

    项目规划

    • if、while、操作符、var/val
    • 继承、sealed
    • 接口
    • lambda
    • 泛型类、泛型接口
    • linq查询表达式
    • case class和模式匹配
    • concept

    高级特性看进度考虑加入:

    • 反射
    • 表达式树
    • 注解

    一些细节:

    • typedef/typealias
    • 嵌套类型、嵌套函数声明
    • 模板字符串
    • object
    • 设计模式语法层简化
    • scala类似中缀操作符的一些语法糖

    相关文章

      网友评论

          本文标题:设计概要

          本文链接:https://www.haomeiwen.com/subject/lhgtextx.html