設計概要

設計概要

注釋

// 注釋
/* 注釋 */

內置類型

[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類似中綴操作符的一些語法糖
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • MySQL 索引設計概要 轉自:http://draveness.me/sql-index-intro.html在...
    vonhng閱讀 430評論 0 0
  • MySQL 索引設計概要 在 MySQL 中,頁的大小一般為 16KB,不過也可能是 8KB、32KB 或者其他值...
    Kee丶閱讀 323評論 0 0
  • 看完山下英子的《斷舍離》之后,我本來想寫一篇《從看得見到看不見》,因為一直沒有好好靜下心來想明白一些事情,所以遲遲...
    海豚的微笑閱讀 491評論 0 0
  • 一、什么是多線程 一個iOS程序就像一個圓,不斷循環,直到將它切斷。一個運行著的程序就是一個進程或者叫做一個任務,...
    小沫360閱讀 13,177評論 4 28
  • 期中考結束,終于又得空碼字,這兩天不寫東西我手都癢癢了(噗哈哈哈哈) 今天寫的主題是圍繞《我們仨》來寫的,書的篇幅...
    春風涼意閱讀 456評論 2 6