木兰 (程式语言)

木兰（Mulan），名称来自模块单元语言（Module Unit Language）的缩写，是一种教学用程式语言，其语法规范来自Lua，编译与执行环境使用Python实现。由中国科学院计算技术研究所入股的中科智芯公司于2020年1月15日发表，团队领导人为中科院副研究员刘雷。这套程式语言是中科智芯公司的重点产品，主要应用于中华人民共和国境内的中小学及幼儿园，作教育使用。

发表之初，研发团队曾称这个程式语言可使用于人工智能与物联网，完全自主研发，编译器与集成开发环境套件也完全由团队开发。在发表后，被质疑是以Python 3.7套件套壳产生。开发者刘雷承认是基于Python做二次开发，完全自主研发以及针对人工智能及物联网应用开发等说法为过度夸大。至2020年1月20日，官方下载网页无法打开，刘雷也被中科院停职接受调查。

## 简介

木兰由中国科学院计算技术研究所国家重点实验室编译组研发团队于2020年1月15日发表。在发表时，开发团队领导人刘雷声称这套程式语言完全由这个研发团队进行自主设计、开发、编程，编译器与集成开发工具套件也完全自主开发，完全掌握核心技术；刘雷认为这个程式语言将会成为“智能物联时代的C语言”。刘雷声称，木兰是为针对人工智能与物联网应用而开发的程式语言；不过因为有易于理解及使用的特性，在尚未被大量使用于应用开发的情况下，木兰已经投入中小学及幼儿园的教育课程中使用。在硬件上，能够搭配中华人民共和国自主研发的龙芯、寒武纪处理器，在操作系统上可搭配Android、iOS、Linux、Windows系统跨平台运作。

中科智芯科技有限公司提供“青少年人工智能教育”相关的服务，其网页上介绍木兰语言时则仅声称该语言是“专为人工智能教育而生的编程语言”。2020年1月20日，中科智芯科技网站所提供的木兰的“语言环境”的安装包名称为ulang-0.2.2.exe。

## 语法内容

因为官方尚没有提供完整开发文件与集成开发套件，这个程式语言的实质内容并不清楚，但在开放 ulang.exe 下载后，开发者社群对它进行逆向工程，对它的特性有基础了解。通过重现项目，发现了更多语法特性。下面是用木兰源码编写的猜 1-100 数字例程，可用 ulang.exe 运行。

```swift
using Cmd in cmd; using exit in sys; using randrange in random

type GuessNumber : Cmd {
  {
    intro, prompt = "I have a number within 100 in mind, guess which one?", "Try: "
    numberInMind = randrange(1000) / 10; history = []; closestDiffSoFar = 100
  }

  func $default(row) {
    try { n = int(row) }
    catch e : ValueError { println("`row` is not a number, try again"); return }
    $history.append(n); $compare(n)
  }

  func $compare(n) {
    if n == $numberInMind { println("Bingo!"); exit() }
    else {
      println("Too " + (n > $numberInMind ? "large" : "small") + "!")
      println("Getting close though") if $gettingCloser()
    }
  }

  func $gettingCloser {
    minDiff = min(map(n -> { diff = n - $numberInMind; return diff > 0 ? diff : -diff }, $history))
    { $closestDiffSoFar = minDiff; return true } if $closestDiffSoFar > minDiff
  }
}
GuessNumber().cmdloop()
```

其语法的最直观特色之一是取消了 Python 的强制缩排，改用大括号。通过语句末尾的分号，支持一行内编写多个语句。

函数方面，可以用 $ 代替 self；在函数无参数时，定义时可以省略；支持 lambda 函数内多个语句。

类型方面，类型扩展使用冒号表示；类型变量需用大括号包围，如例程中的 intro、prompt 等。

内置函数方面，添加了 println；isinstance 改为 isa。

注释段用 /* */，注释行用 //。

关键词方面有诸多修改，比如由 Python 使用的 def 改成 func，类似于Swift、Go与PHP；try...except 改为 try...catch；None 改为 nil，True/False 改为 true/false；class 改为 type 等等。

不支援汉字作为变数名称，保留的关键字中也没有汉字，因此不能以中文来进行编程。与此相比，Python 3可以使用Unicode文字（包括汉字）作为变量名。

## 实现原理

在程序执行时，用 RPly 进行词法与语法分析后生成 Python 抽象语法树，调用 Python 内置函数 compile 生成可执行码，再调用 Python 内置函数 exec 运行。运行速度与 Python 相近。由于基于 Python 的运行时环境，可以跨平台运作。

除了运行木兰源码，ulang.exe 还有参数支持周边功能。其中 --dump-python 借助 codegen 库将木兰源码生成对应的 Python 代码。

通过扩展 Python 内置函数 __import__，支持导入木兰模块，同时仍支持导入 Python 模块，而且不需 __init__.py 即可找到模块。语法与 Python 基本对应。

```python
using some_module
using module1, module2
using some_method in some_module
using * in some_module
using * in .
using ceil in math
```

## 关于核心技术的争议

在其执行档ulang-0.2.2.exe开放下载后，CSDN网友“沉迷单车的追风少年”等开发者发现，这个执行档是直接用PyInstaller将Python 3.7套件打包成一个执行档，图标直接使用Python的官方图标。在解开后，其内容大部分都是python 3.7的官方套件，包括python的建构环境、套件等，自行撰写的部分不多，与其宣称完全自主开发不同。开发者刘雷回应，在8位元单芯片上的编译器是由他们团队自主开发，在32位元处理器上则是基于Python二次开发，其语法规范来自Lua，但扩充了资料类型，主要使用于中小学教育，而不是人工智能与物联网开发。1月19日，相关负责人刘雷被中科院停职检查。之后刘雷则表示木兰项目没有使用任何科研经费。1月19日，官方下载网页已经无法打开。

## 处罚

2020年1月23日，中国科学院计算技术研究所发布《关于“木兰”语言问题的调查与处理意见》，认为刘雷在“木兰”语言的宣传活动中存在欺瞒、虚假陈述和夸大宣传的行为，取消其五年内专业技术岗位晋升的申请资格，取消三年内科研项目的申请资格，岗位等级从工程师一级降为助理工程师一级。

## 评论

《经济日报》（中国经济网）认为，学术界的丑闻“让人痛心”，认为科学不容玷污，应加强科学道德和学风建设。认为科研工作者应该“以身作则，还学术、还科研一片净土”。

## 重现项目

由于木兰源码并未由官方发布，于1月16日在知乎提出问题‘“木兰”编程语言有什么特色？’的编程语言爱好者吴烜随即创建了木兰编程语言重现项目，并开源在Gitee。2020年11月25日，该项目在开源中国（OSCHINA）主办的评选活动中位列“最积极运营项目”前20名。

此项目通过修改词法分析部分，使木兰支持了中文标识符。猜数字例程改用中文命名如下。

```swift
using Cmd in cmd; using exit in sys; using 随机范围数 in 随机数

type 猜数字 : Cmd {
  {
    intro, prompt = "木兰想了个 100 之内的数，猜是几？", "猜猜吧: "
    想的 = 随机范围数(1000) / 10; 历史 = []; 至今最近 = 100
  }

  func $default(行) {
    try { 数 = int(行) }
    catch 例外 : ValueError { println("`行` 不是数，请再试"); return }
    $历史.append(数); $比较(数)
  }

  func $比较(数) {
    if 数 == $想的 { println("中了!"); exit() }
    else {
      println("太" + (数 > $想的 ? "大" : "小") + "了!")
      println("不过接近咯") if $接近了()
    }
  }

  func $接近了 {
    最近 = min(map(数 -> { 差 = 数 - $想的; return 差 > 0 ? 差 : -差 }, $历史))
    { $至今最近 = 最近; return true } if $至今最近 > 最近
  }
}
猜数字().cmdloop()
```

## 基本资料

- 日语原文：木兰、Mulan
- 编程范型：多范式：面向对象
- 设计者：刘雷
- 开发者：中科智芯公司
- 发行日期：2020年1月15日
- 软件版本周期：0.2.2
- 操作系统：跨平台