设计概要
注释
// 注释
/* 注释 */
内置类型
[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类似中缀操作符的一些语法糖
网友评论