01 · effect
效果进类型
默认是纯的:碰 IO 要标 !io,自己声明的效果由 with handle 应答。
effect Ask {
fn ask() -> Int
}
fn total() -> Int !Ask =
ask() + ask()
pub fn main() -> Unit !io = {
with handle Ask { ask() => 21 }
println("${total()}")
}
42
−18° 夜色将尽
type · match · effect · !io
一门小而优雅的函数式语言:不可变数据、代数数据类型与穷尽匹配、写进类型签名的效果。
type Shape =
| Circle(r: Float)
| Rect(w: Float, h: Float)
fn area(s: Shape) -> Float =
match s {
Circle(r) -> 3.14159 * r * r
Rect(w, h) -> w * h
}
pub fn main() -> Unit !io =
[Circle(1.0), Rect(2.0, 3.0)]
|> map(area)
|> fold(0.0, (a, x) => a + x)
|> t => println("total: ${t}")
−12° 海天初分 · 三个概念
函数碰了什么、提前算了什么、匹配了什么,都由编译器检查。
默认是纯的:碰 IO 要标 !io,自己声明的效果由 with handle 应答。
effect Ask {
fn ask() -> Int
}
fn total() -> Int !Ask =
ask() + ask()
pub fn main() -> Unit !io = {
with handle Ask { ask() => 21 }
println("${total()}")
}
comptime { ... } 在编译期运行普通函数,结果烧进常量池。
fn fib(n: Int) -> Int =
if n < 2 { n }
else { fib(n - 1) + fib(n - 2) }
const FIB10: Int =
comptime { fib(10) }
pub fn main() -> Unit !io =
println("fib(10) = ${FIB10}")
不可变的代数数据;漏了一种情况的 match 编译不过。
type Shape =
| Circle(r: Float)
| Rect(w: Float, h: Float)
| Point
fn describe(s: Shape) -> String =
match s {
Circle(r) -> "circle ${r}"
Rect(w, h) -> "rect ${w} x ${h}"
Point -> "a point"
}
pub fn main() -> Unit !io = {
let xs = [Circle(1.0), Point]
for s in xs {
println(describe(s))
}
}
−6° 天色渐明 · 两个后端
JVM 字节码与 C 是平级的两个后端。每次 push,差分语料在两边各跑一遍,输出有一处不同就构建失败。
−3° 破晓 · GPU
cuTile kernel 是一个带具名效果的普通 Dawn 函数,降为 CUDA Tile IR。纯的假设备在没有 GPU 的机器上给出同一个答案。
102/105 个公开 Tile IR opcode 已实现,每个都在 GPU 上与宿主参考对拍过。 覆盖表、门禁与设备台账都在 cuTile 页上 →
fn vadd(a: Param[Float], b: Param[Float], out: Param[Float]) -> Unit !Dev = {
let ta = load_cell(a)
let tb = load_cell(b)
store_cell(out, add(ta, tb))
}
dawn run 打印的 Tile IR 里的那次加法%19 = addf %12, %17 rounding<nearest_even> : tile<128xf64>!Dev
运行它会记下它发出的操作;记录变成 Tile IR,再由 tileiras 汇编成 cubin。
tile-gpu-diff 把每个 kernel 与宿主参考对拍;台账没覆盖到的改动 CI 会拦下。fn run(xs: List[Float], ys: List[Float]) -> Result[List[Float], ForeignError] !Gpu = {
let n = len(xs)
let a = alloc(F64, n)?
let b = alloc(F64, n)?
let out = alloc(F64, n)?
copy_from_host(a, xs)?
copy_from_host(b, ys)?
launch("vadd", blocks(n), [erase(buffer_arg(a)), erase(buffer_arg(b)), erase(buffer_arg(out))])?
sync()?
let got = copy_to_host(out)?
free(a)?
free(b)?
free(out)?
Ok(got)
}
dawn run 在 with_gpu_fake 下打印的那一行vadd on the fake device: [11.0, 22.0, 33.0, 44.0]!Gpu
with_gpu_real 由 CUDA driver 应答,with_gpu_fake 由宿主内存应答。
libcuda;在 JVM 上,真设备的 launch 会被拒绝。!Gpu 程序能在测试里跑,两个后端都行,不需要 GPU。0° 日出 · 安装
每个 release 都带两套工具链,各附 SHA-256。
dawnc-linux-x86_64
base=https://github.com/dawnop/dawn-lang/releases/latest/download
curl -fsSLO $base/dawnc-linux-x86_64
curl -fsSLO $base/dawnc-linux-x86_64.sha256
sha256sum -c dawnc-linux-x86_64.sha256
chmod +x dawnc-linux-x86_64
sudo mv dawnc-linux-x86_64 /usr/local/bin/dawnc
printf 'pub fn main() -> Unit !io = println("hello, dawn")\n' \
> hello.dawn
dawnc run hello.dawn
hello, dawn
dawn-selfhost.jar
base=https://github.com/dawnop/dawn-lang/releases/latest/download
curl -fsSLO $base/dawn-selfhost.jar
curl -fsSLO $base/dawn-selfhost.jar.sha256
# macOS: shasum -a 256 -c
sha256sum -c dawn-selfhost.jar.sha256
printf 'pub fn main() -> Unit !io = println("hello, dawn")\n' \
> hello.dawn
java -jar dawn-selfhost.jar run hello.dawn
hello, dawn
最新 release · 教程第 1 章 · 规范 · 示例