GitHub - Storyyeller/polysubml-demo: 一种具有子类型、多态性、高阶类型和全局类型推断的简单类似 ML 的语言

PolySubML 是一种实验性的类 ML 编程语言,具有以下特征:

  • 结构子类型(又名“编译时鸭式类型”)
  • 全局类型推断(单态代码完全无需类型注解)
  • 多态函数
  • 高阶类型
  • 存在类型
  • 等价递归类型
  • 无不可命名或不可想象类型
  • 最坏情况多项式时间类型检查

可在浏览器中在线尝试这里,它不用于生产,而是作为新型类型推断算法和其他语言设计技术的演示。

示例

  • 递归函数实现的 FizzBuzz:

    let rec fizzbuzz = fun i -> (
    print (if i % 3!= 0 then
      if i % 5!= 0 then 
        "FizzBuzz"
      else      
        "Fizz"
    else 
      if i % 5!= 0 then
        "Buzz"
      else 
        i 
    );
    if i < 50 then 
      fizzbuzz (i+1)
    else 
      0
    );
    fizzbuzz 0;
  • 循环和可变计数器实现的 FizzBuzz:

    let vars = {mut i=0};
    loop if vars.i >= 50 then `Break 0 else (
    let i = vars.i <- vars.i + 1;
    print (if i % 3 == 0 then
      if i % 5 == 0 then 
        "FizzBuzz"
      else      
        "Fizz"
    else 
      if i % 5 == 0 then
        "Buzz"
      else 
        i 
    );
    `Continue 0
    );

入门
可在浏览器中在线尝试[https://storyyeller.github.io...],从源码构建需安装lalrpopwasm-pack,然后运行:

lalrpop src/grammar.lalr
wasm-pack build --target web

PolySubML 快速游览

  • 基本语法:支持(* style *)// style注释, whitespace 除避免歧义外无意义,有boolintfloatstr等基本类型,整数和浮点数运算符不同,字符串连接用^
  • 表达式和语句:是表达式导向语言,几乎一切都是表达式,有let v = expr1 in expr2let v = expr1; expr2两种赋值语法,还有print语句,语句块必须以表达式结尾,顶层可以只有语句。
  • 条件语句if是表达式,else部分需用括号包裹,避免歧义。
  • 记录和字段:通过{name1=val1; name2=val2;...}定义,可通过.name访问字段,有特殊简写语法,记录匿名且结构类型,多字段记录是少字段记录的子类型,访问未定义字段会导致编译错误。
  • 解构和 let 模式:可通过let {field1=foo; field2=bar; field3=baz} = record;解构记录,可省略=部分,记录解构可嵌套,变量模式_用于忽略匹配值。
  • 可变字段:变量不可重新赋值,仅可变记录字段有可变状态,通过mut前缀创建和更新可变字段,记录使用引用语义,字段赋值表达式返回旧值,可用于值交换。
  • 元组:通过a, b, c,...创建和解构元组,元组是特殊的记录,有._0._1等访问方式,无 0 或 1 元素元组的简写语法,元组不支持可变字段和存在类型。
  • 函数:所有函数需接受一个参数,通过fun <arg> -> <expr>定义,函数调用通过后缀参数,函数应用是右结合的,可通过元组或记录模拟多参数函数,也可使用柯里化,但不推荐,可使用递归 let 表达式定义递归函数,let rec允许多个变量绑定实现相互递归。
  • 变体和匹配:通过\tag value定义变体,可使用变体模式解构变体值,需使用match表达式根据变体值执行不同代码,每个匹配分支可访问原始值的静态类型,match`表达式必须 exhaustive,匹配是顺序无关的,仅匹配最顶层标签,可使用通配符匹配未处理的变体。
  • 类型注解:强大的类型推断使除多态代码外无需类型注解,可在表达式、变量模式、记录字面量、函数定义等位置添加类型注解,any表示任意值,never表示不可达值,注意函数类型注解的细节,如fun x: int ->...int注解返回类型等。
  • 多态性:为实现代码复用需要多态性,定义通用函数需添加类型参数,类型参数在函数体中可被推断,通用函数类型可作为普通类型传递,需显式实例化通用函数,部分实例化需显式注解,并非所有代码都需要多态性,存在类型是通用类型的镜像,与记录相关,可通过type name;解构和注解,存在类型可显式或隐式实例化,遵循与通用类型相同的规则,PolySubML 支持有限形式的显式类型联合和交集。
  • 循环和递归:递归函数在处理大型数据时可能因递归深度限制而崩溃,PolySubML 也支持通过loop表达式实现 imperative 风格的迭代,需使用可变状态(带可变字段的记录)。
阅读 8
0 条评论