快速上手

本指南带你从一个空的 MoonBit 模块出发,写出对 arithmetic 每个层级各使用一次的代码。core 教程在此基础上继续,给出完整的任务。

安装与导入

把本包添加到 moon.mod:

moon add Luna-Flow/arithmetic@0.5.0

在每个使用它的包的 moon.pkg 中导入它,并使用 Luna Flow 代码约定的别名:

import {
  "Luna-Flow/arithmetic" @lf_arith,
}

如果还需要 Ring 或 Field 等代数 trait,请添加 Luna-Flow/luna-generic,别名为 @lf_alg。

依赖能力,而非类型

针对函数所用到的 trait 来编写它。Add 和 Mul 是 MoonBit 的运算符 trait;Sqrt 来自本包:

fn[T : Add + Mul + @lf_arith.Sqrt] norm2(x : T, y : T) -> T {
  @lf_arith.Sqrt::sqrt(x * x + y * y)
}

test "norm" {
  inspect(norm2(3.0, 4.0), content="5")
}

norm2 接受 Float、Double,以及你自己实现了这三个 trait 的任何类型。

让失败显式化

检查 trait 返回 Result。传入一个 ArithmeticContext;原生实例不会读取它,但十进制后端会:

test "checked division" {
  let ctx = @lf_arith.ArithmeticContext::decimal64()
  inspect(@lf_arith.DivChecked::div_checked(1.0, 8.0, ctx).unwrap(), content="0.125")
  match @lf_arith.DivChecked::div_checked(1.0, 0.0, ctx) {
    Ok(_) => fail("unexpected quotient")
    Err(e) => inspect(e.message, content="division by zero")
  }
}

读取诊断

上下文 trait 还会返回诊断。把 224+12^{24} + 1 转换为 Float 会丢失最后一位,结果会如实反映这一点:

test "contextual conversion" {
  let ctx = @lf_arith.ArithmeticContext::new(24)
  let out : @lf_arith.ArithmeticOutcome[Float] = @lf_arith.IntegralContextual::from_int_contextual(
    16_777_217, ctx,
  ).unwrap()
  inspect(out.value, content="16777216")
  inspect(out.diagnostics.inexact, content="true")
}

Float 和 Double 的大多数上下文运算不检测舍入;API 页说明了哪些会检测。

后续阅读