diff --git a/next/locales/zh_CN/LC_MESSAGES/index.po b/next/locales/zh_CN/LC_MESSAGES/index.po index e2312028..3e64ff67 100644 --- a/next/locales/zh_CN/LC_MESSAGES/index.po +++ b/next/locales/zh_CN/LC_MESSAGES/index.po @@ -9,7 +9,7 @@ msgid "" msgstr "" "Project-Id-Version: MoonBit Document \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-11-27 13:11+0800\n" +"POT-Creation-Date: 2024-12-18 11:20+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: zh_CN\n" @@ -20,10 +20,6 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Generated-By: Babel 2.16.0\n" -#: ../../index.md:15 -msgid "Contents:" -msgstr "目录:" - #: ../../index.md:1 msgid "MoonBit Documentation" msgstr "MoonBit 文档" @@ -64,9 +60,3 @@ msgid "" "making developing MoonBit a unique experience." msgstr "[工具链](./toolchain/index.md): 介绍所有工具链,使 MoonBit 的开发成为独特体验。" -#~ msgid "" -#~ "[Toolchains](./toolchains/index.md): Introduction to " -#~ "all the toolchains making developing " -#~ "MoonBit a unique experience." -#~ msgstr "" - diff --git a/next/locales/zh_CN/LC_MESSAGES/language.po b/next/locales/zh_CN/LC_MESSAGES/language.po index ddd0dcb1..b619bc23 100644 --- a/next/locales/zh_CN/LC_MESSAGES/language.po +++ b/next/locales/zh_CN/LC_MESSAGES/language.po @@ -9,7 +9,7 @@ msgid "" msgstr "" "Project-Id-Version: MoonBit Document \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-12-03 16:21+0800\n" +"POT-Creation-Date: 2024-12-18 11:20+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: zh_CN\n" @@ -20,8 +20,92 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Generated-By: Babel 2.16.0\n" +#: ../../language/docs.md:1 +msgid "Documentation" +msgstr "" + +#: ../../language/docs.md:3 +msgid "Doc Comments" +msgstr "" + +#: ../../language/docs.md:5 +msgid "" +"Doc comments are comments prefix with `///` in each line in the leading " +"of toplevel structure like `fn`,`let`,`enum`,`struct`,`type`. The doc " +"comments contains a markdown text and several pragmas." +msgstr "" + +#: ../../language/docs.md:7 +msgid "" +"/// Return a new array with reversed elements.\n" +"///\n" +"/// # Example\n" +"///\n" +"/// ```\n" +"/// reverse([1,2,3,4]) |> println()\n" +"/// ```\n" +"fn reverse[T](xs : Array[T]) -> Array[T] {\n" +" ...\n" +"}\n" +msgstr "" + +#: ../../language/docs.md:13 +msgid "Pragmas" +msgstr "" + +#: ../../language/docs.md:15 +msgid "" +"Pragmas are annotations inside doc comments. They all take the form `/// " +"@word ...`. The _word_ indicates the type of pragma and is followed " +"optionally by several _word_ or string literals. Pragmas do not normally " +"affect the meaning of programs. Unrecognized pragmas will be reported as " +"warnings." +msgstr "" + +#: ../../language/docs.md:17 +msgid "Alert Pragmas" +msgstr "" + +#: ../../language/docs.md:19 +msgid "" +"Alert pragmas in doc comments of functions will be reported when those " +"functions are referenced. This mechanism is a generalized way to mark " +"functions as `deprecated` or `unsafe`." +msgstr "" + +#: ../../language/docs.md:21 +msgid "It takes the form `@alert category \"alert message...\"`." +msgstr "" + +#: ../../language/docs.md:23 +msgid "" +"The category can be an arbitrary identifier. It allows configuration to " +"decide which alerts are enabled or turned into errors." +msgstr "" + +#: ../../language/docs.md:26 +msgid "" +"/// @alert deprecated \"Use foo2 instead\"\n" +"pub fn foo() -> Unit {\n" +" ...\n" +"}\n" +"\n" +"/// @alert unsafe \"Div will cause an error when y is zero\"\n" +"pub fn div(x : Int, y : Int) -> Int {\n" +" ...\n" +"}\n" +"\n" +"test {\n" +" // Warning (Alert deprecated): Use foo2 instead\n" +" foo()\n" +" // Warning (Alert unsafe): Div will cause an error when y is zero\n" +" div(1, 2) |> ignore\n" +"}\n" +msgstr "" + #: ../../language/error-handling.md:1 -msgid "Error handling in MoonBit" +#, fuzzy +msgid "Error handling" msgstr "MoonBit 中的错误处理" #: ../../language/error-handling.md:3 @@ -35,17 +119,365 @@ msgstr "" "[MoonBit 之旅](../tutorial/tour.md)。" #: ../../language/error-handling.md:7 +msgid "Error types" +msgstr "" + +#: ../../language/error-handling.md:9 +msgid "" +"The error values used in MoonBit must have an error type. An error type " +"can be defined in the following forms:" +msgstr "" + +#: ../../language/error-handling.md:12 +msgid "" +"type! E1 Int // error type E1 has one constructor E1 with an Int payload\n" +"\n" +"type! E2 // error type E2 has one constructor E2 with no payload\n" +"\n" +"type! E3 { // error type E3 has three constructors like a normal enum " +"type\n" +" A\n" +" B(Int, x~ : String)\n" +" C(mut x~ : String, Char, y~ : Bool)\n" +"}\n" +msgstr "" + +#: ../../language/error-handling.md:19 +msgid "" +"The return type of a function can include an error type to indicate that " +"the function might return an error. For example, the following function " +"`div` might return an error of type `DivError`:" +msgstr "" + +#: ../../language/error-handling.md:23 +msgid "" +"type! DivError String\n" +"\n" +"fn div(x : Int, y : Int) -> Int!DivError {\n" +" if y == 0 {\n" +" raise DivError(\"division by zero\")\n" +" }\n" +" x / y\n" +"}\n" +msgstr "" + +#: ../../language/error-handling.md:30 +msgid "" +"Here, the keyword `raise` is used to interrupt the function execution and" +" return an error." +msgstr "" + +#: ../../language/error-handling.md:33 +msgid "The Default Error Type" +msgstr "" + +#: ../../language/error-handling.md:35 +msgid "" +"MoonBit provides a default error type `Error` that can be used when the " +"concrete error type is not important. For convenience, you can annotate " +"the function name or the return type with the suffix `!` to indicate that" +" the `Error` type is used. For example, the following function signatures" +" are equivalent:" +msgstr "" + +#: ../../language/error-handling.md:40 +msgid "" +"fn f() -> Unit! {\n" +" ...\n" +"}\n" +"\n" +"fn g!() -> Unit {\n" +" ...\n" +"}\n" +"\n" +"fn h() -> Unit!Error {\n" +" ...\n" +"}\n" +msgstr "" + +#: ../../language/error-handling.md:47 +msgid "" +"For anonymous function and matrix function, you can annotate the keyword " +"`fn` with the `!` suffix to achieve that. For example," +msgstr "" + +#: ../../language/error-handling.md:50 +msgid "" +"type! IntError Int\n" +"\n" +"fn h(f : (Int) -> Int!, x : Int) -> Unit {\n" +" ...\n" +"}\n" +"\n" +"fn g() -> Unit {\n" +" let _ = h(fn! { x => raise IntError(x) }, 0)\n" +" let _ = h(fn!(x) { raise IntError(x) }, 0)\n" +"\n" +"}\n" +msgstr "" + +#: ../../language/error-handling.md:56 +msgid "" +"As shown in the above example, the error types defined by `type!` can be " +"used as value of the type `Error` when the error is raised." +msgstr "" + +#: ../../language/error-handling.md:59 +msgid "" +"Note that only error types or the type `Error` can be used as errors. For" +" functions that are generic in the error type, you can use the `Error` " +"bound to do that. For example," +msgstr "" + +#: ../../language/error-handling.md:63 +msgid "" +"// Result::unwrap_or_error\n" +"fn unwrap_or_error[T, E : Error](result : Result[T, E]) -> T!E {\n" +" match result {\n" +" Ok(x) => x\n" +" Err(e) => raise e\n" +" }\n" +"}\n" +msgstr "" + +#: ../../language/error-handling.md:69 +msgid "" +"Since the type `Error` can include multiple error types, pattern matching" +" on the `Error` type must use the wildcard `_` to match all error types. " +"For example," +msgstr "" + +#: ../../language/error-handling.md:72 +msgid "" +"type! E4\n" +"\n" +"type! E5\n" +"\n" +"fn f(e : Error) -> Unit {\n" +" match e {\n" +" E4 => println(\"E1\")\n" +" E5 => println(\"E2\")\n" +" _ => println(\"unknown error\")\n" +" }\n" +"}\n" +msgstr "" + +#: ../../language/error-handling.md:78 +msgid "Handling Errors" +msgstr "" + +#: ../../language/error-handling.md:80 +msgid "There are three ways to handle errors:" +msgstr "" + +#: ../../language/error-handling.md:82 +msgid "" +"Append `!` after the function name in a function application to rethrow " +"the error directly in case of an error, for example:" +msgstr "" + +#: ../../language/error-handling.md:85 +msgid "" +"fn div_reraise(x : Int, y : Int) -> Int!DivError {\n" +" div!(x, y) // Rethrow the error if `div` raised an error\n" +"}\n" +msgstr "" + +#: ../../language/error-handling.md:91 +msgid "" +"Append `?` after the function name to convert the result into a first-" +"class value of the `Result` type, for example:" +msgstr "" + +#: ../../language/error-handling.md:94 +msgid "" +"test {\n" +" let res = div?(6, 3)\n" +" inspect!(res, content=\"Ok(2)\")\n" +" let res = div?(6, 0)\n" +" inspect!(\n" +" res,\n" +" content=\n" +" #|Err(\"division by zero\")\n" +" ,\n" +" )\n" +"}\n" +msgstr "" + +#: ../../language/error-handling.md:100 +msgid "Use `try` and `catch` to catch and handle errors, for example:" +msgstr "" + +#: ../../language/error-handling.md:102 +msgid "" +"fn main {\n" +"try {\n" +" div!(42, 0)\n" +"} catch {\n" +" DivError(s) => println(s)\n" +"} else {\n" +" v => println(v)\n" +"}\n" +"}\n" +msgstr "" + +#: ../../language/error-handling.md:111 ../../language/fundamentals.md:115 +#: ../../language/fundamentals.md:147 ../../language/fundamentals.md:174 +#: ../../language/fundamentals.md:198 ../../language/fundamentals.md:590 +#: ../../language/fundamentals.md:604 ../../language/fundamentals.md:618 +#: ../../language/fundamentals.md:632 ../../language/fundamentals.md:644 +#: ../../language/fundamentals.md:661 ../../language/fundamentals.md:699 +#: ../../language/fundamentals.md:746 ../../language/fundamentals.md:760 +#: ../../language/fundamentals.md:883 ../../language/fundamentals.md:919 +#: ../../language/fundamentals.md:950 ../../language/fundamentals.md:977 +#: ../../language/fundamentals.md:1006 ../../language/fundamentals.md:1026 +#: ../../language/fundamentals.md:1060 ../../language/fundamentals.md:1074 +#: ../../language/methods.md:91 +msgid "Output" +msgstr "" + +#: ../../language/error-handling.md:111 +#, fuzzy +msgid "division by zero\n" +msgstr "示例:除零" + +#: ../../language/error-handling.md:115 +msgid "" +"Here, `try` is used to call a function that might throw an error, and " +"`catch` is used to match and handle the caught error. If no error is " +"caught, the catch block will not be executed and the `else` block will be" +" executed instead." +msgstr "" + +#: ../../language/error-handling.md:119 +msgid "" +"The `else` block can be omitted if no action is needed when no error is " +"caught. For example:" +msgstr "" + +#: ../../language/error-handling.md:122 +msgid "" +"try {\n" +" println(div!(42, 0))\n" +"} catch {\n" +" _ => println(\"Error\")\n" +"}\n" +msgstr "" + +#: ../../language/error-handling.md:129 +msgid "" +"The `catch` keyword is optional, and when the body of `try` is a simple " +"expression, the curly braces can be omitted. For example:" +msgstr "" + +#: ../../language/error-handling.md:132 +msgid "" +"let a = try {\n" +" div!(42, 0)\n" +"} catch {\n" +" _ => 0\n" +"}\n" +"println(a)\n" +msgstr "" + +#: ../../language/error-handling.md:139 +msgid "" +"The `!` and `?` attributes can also be used on method invocation and pipe" +" operator. For example:" +msgstr "" + +#: ../../language/error-handling.md:142 +msgid "" +"type T Int\n" +"\n" +"type! E Int derive(Show)\n" +"\n" +"fn k(self : T) -> Unit!E {\n" +" ...\n" +"}\n" +"\n" +"fn l() -> Unit!E {\n" +" let x = T(42)\n" +" k!(x)\n" +" x.k!()\n" +" x |> k!()\n" +"}\n" +msgstr "" + +#: ../../language/error-handling.md:148 +msgid "" +"However for infix operators such as `+` `*` that may raise an error, the " +"original form has to be used, e.g. `x.op_add!(y)`, `x.op_mul!(y)`." +msgstr "" + +#: ../../language/error-handling.md:151 +msgid "" +"Additionally, if the return type of a function includes an error type, " +"the function call must use `!` or `?` for error handling, otherwise the " +"compiler will report an error." +msgstr "" + +#: ../../language/error-handling.md:155 +msgid "Error Inference" +msgstr "" + +#: ../../language/error-handling.md:157 +msgid "" +"Within a `try` block, several different kinds of errors can be raised. " +"When that happens, the compiler will use the type `Error` as the common " +"error type. Accordingly, the handler must use the wildcard `_` to make " +"sure all errors are caught. For example," +msgstr "" + +#: ../../language/error-handling.md:162 +msgid "" +"fn f1() -> Unit!E1 {\n" +" ...\n" +"}\n" +"\n" +"fn f2() -> Unit!E2 {\n" +" ...\n" +"}\n" +"\n" +"try {\n" +" f1!()\n" +" f2!()\n" +"} catch {\n" +" E1(_) => ...\n" +" E2 => ...\n" +" _ => ...\n" +"}\n" +msgstr "" + +#: ../../language/error-handling.md:169 +msgid "" +"You can also use `catch!` to rethrow the uncaught errors for convenience." +" This is useful when you only want to handle a specific error and rethrow" +" others. For example," +msgstr "" + +#: ../../language/error-handling.md:173 +msgid "" +"try {\n" +" f1!()\n" +" f2!()\n" +"} catch! {\n" +" E1(_) => ...\n" +"}\n" +msgstr "" + +#: ../../language/error-handling.md:180 msgid "Example: Division by Zero" msgstr "示例:除零" -#: ../../language/error-handling.md:9 +#: ../../language/error-handling.md:182 msgid "" "We'll write a small example to demonstrate the basics of MoonBit's error " "handling system. Consider the following `div` function which'll raise an " "error on division by zero:" msgstr "我们将编写一个小例子来演示 MoonBit 错误处理系统的基础知识。考虑以下 `div` 函数,它将在除零时引发错误:" -#: ../../language/error-handling.md:13 +#: ../../language/error-handling.md:186 msgid "" "type! DivisionByZeroError String\n" "fn div(x : Int, y : Int) -> Int!DivisionByZeroError {\n" @@ -56,7 +488,7 @@ msgid "" "}\n" msgstr "" -#: ../../language/error-handling.md:23 +#: ../../language/error-handling.md:196 msgid "" "In before, we would typically use `type` to define a wrapper type which " "wraps around some existing foreign type. Here however, we append `type` " @@ -66,11 +498,11 @@ msgstr "" "在以前,我们通常使用 `type` 来定义一个包装器类型,该类型包装了某些现有的外部类型。然而,在这里,我们使用 `!` 将 `type` 附加到" " `DivisionByZeroError`,以定义一个错误类型,该类型包装了 `String`。" -#: ../../language/error-handling.md:27 +#: ../../language/error-handling.md:200 msgid "`type! E S` construct a error type `E` from `S`" msgstr "`type! E S` 从 `S` 构造一个错误类型 `E`" -#: ../../language/error-handling.md:29 +#: ../../language/error-handling.md:202 msgid "" "Just like `type`, `type!` may have a payload like the above " "`DivisionByZeroError`, or may not, or may even have multiple constructors" @@ -79,7 +511,7 @@ msgstr "" "就像 `type` 一样,`type!` 可能有一个像上面的 `DivisionByZeroError` 那样的数据,也可能没有,甚至可能像普通的" " `enum` 一样有多个构造器:" -#: ../../language/error-handling.md:31 +#: ../../language/error-handling.md:204 msgid "" "type! ConnectionError {\n" " BrokenPipe(Int,String)\n" @@ -89,7 +521,7 @@ msgid "" "}\n" msgstr "" -#: ../../language/error-handling.md:40 +#: ../../language/error-handling.md:213 msgid "" "To utilize `DivisionByZeroError` type, we would usually define a function" " which may raise error by denoting its return type like `T ! E` in the " @@ -103,41 +535,41 @@ msgstr "" "`Int!DivisionByZeroError`。错误可以使用 `raise e` 抛出,其中 `e` 是 `E` 的实例,可以使用 `S` " "的默认构造函数构造。" -#: ../../language/error-handling.md:47 +#: ../../language/error-handling.md:220 msgid "" "Any instance of an error is a second class object. Meaning it may only " "appear in the return value. And if it does appear, the function signature" " has to be adjusted to match with the return type." msgstr "任何错误的实例都是一个二等公民对象。这意味着它只能出现在返回值中。如果返回值包含错误,函数签名必须调整以匹配返回类型。" -#: ../../language/error-handling.md:51 +#: ../../language/error-handling.md:224 msgid "" "The `test` block in MoonBit may also be seen as a function, with a return" " type of Unit!Error." msgstr "MoonBit 中的 `test` 块也可以看作是一个函数,返回类型为 Unit!Error。" -#: ../../language/error-handling.md:54 +#: ../../language/error-handling.md:227 msgid "Calling an error-able function" msgstr "调用一个可出错的函数" -#: ../../language/error-handling.md:56 +#: ../../language/error-handling.md:229 msgid "" "an error-able function is usually called in 2 manners: `f!(...)` and " "`f?(...)`." msgstr "一个可出错的函数通常有两种调用方式:`f!(...)` 和 `f?(...)`。" -#: ../../language/error-handling.md:58 +#: ../../language/error-handling.md:231 msgid "As-is calling" msgstr "直接调用" -#: ../../language/error-handling.md:60 +#: ../../language/error-handling.md:233 msgid "" "`f!(...)` calls the function directly. The possible error must be dealt " "in the function that calls `f`. We can either re-raising it without " "actually dealing with the error:" msgstr "`f!(...)` 直接调用函数。可能的错误必须在调用 `f` 的函数中处理。我们可以重新抛出它,而不实际处理错误:" -#: ../../language/error-handling.md:64 +#: ../../language/error-handling.md:237 msgid "" "// We have to match the error type of `div2` with `div`\n" "fn div2(x : Int, y : Int) -> Int!DivisionByZeroError {\n" @@ -145,11 +577,11 @@ msgid "" "}\n" msgstr "" -#: ../../language/error-handling.md:71 +#: ../../language/error-handling.md:244 msgid "or use `try...catch` block like in many other languages:" msgstr "或者像其他许多语言一样使用 `try...catch` 块:" -#: ../../language/error-handling.md:73 +#: ../../language/error-handling.md:246 msgid "" "fn div3(x : Int, y : Int) -> Unit {\n" " try {\n" @@ -162,7 +594,7 @@ msgid "" "}\n" msgstr "" -#: ../../language/error-handling.md:85 +#: ../../language/error-handling.md:258 msgid "" "The `catch...` clause has similar semantics like pattern matching. We can" " unwrap the error to retrieve the underlying `String` and print it. " @@ -172,7 +604,7 @@ msgstr "" "`catch...` 子句的语义类似于模式匹配。我们可以解包错误以检索底层的 `String` 并打印它。此外,还有一个 `else` 子句来处理" " `try...` 块的值。" -#: ../../language/error-handling.md:89 +#: ../../language/error-handling.md:262 msgid "" "fn test_try() -> Result[Int, Error] {\n" " // compiler can figure out the type of a local error-able function.\n" @@ -184,7 +616,7 @@ msgid "" "}\n" msgstr "" -#: ../../language/error-handling.md:100 +#: ../../language/error-handling.md:273 msgid "" "Curly braces may be omitted if the body of try is a one-liner " "(expression). The `catch` keyword can also be omitted as well. In the " @@ -195,7 +627,7 @@ msgstr "" "如果 `try` 的主体是一行代码(表达式),则大括号可以省略。`catch` 关键字也可以省略。在 `try` " "主体可能引发不同错误的情况下,可以使用特殊的 `catch!` 来捕获一些错误,同时重新抛出其他未捕获的错误:" -#: ../../language/error-handling.md:104 +#: ../../language/error-handling.md:277 msgid "" "type! E1\n" "type! E2\n" @@ -212,15 +644,15 @@ msgid "" "}\n" msgstr "" -#: ../../language/error-handling.md:120 +#: ../../language/error-handling.md:293 msgid "Convert to Result" msgstr "转换为 Result" -#: ../../language/error-handling.md:122 +#: ../../language/error-handling.md:295 msgid "Extracting values" msgstr "提取值" -#: ../../language/error-handling.md:124 +#: ../../language/error-handling.md:297 msgid "" "A object of type `Result` is a first class value in MoonBit. `Result` has" " 2 constructors: `Ok(...)` and `Err(...)` where the former accept a first" @@ -229,13 +661,13 @@ msgstr "" "`Result` 类型的对象是 MoonBit 中的一等公民。`Result` 有 2 个构造器:`Ok(...)` 和 " "`Err(...)`,前者接受一个一等公民对象,后者接受一个错误对象。" -#: ../../language/error-handling.md:126 +#: ../../language/error-handling.md:299 msgid "" "With `f?(...)`, the return type `T!E` is turned into `Result[T,E]`. We " "may use pattern matching to extract value from it:" msgstr "使用 `f?(...)`,返回类型 `T!E` 被转换为 `Result[T,E]`。我们可以使用模式匹配从中提取值:" -#: ../../language/error-handling.md:128 +#: ../../language/error-handling.md:301 msgid "" "let res = div?(10, 0)\n" "match res {\n" @@ -244,11 +676,11 @@ msgid "" "}\n" msgstr "" -#: ../../language/error-handling.md:136 +#: ../../language/error-handling.md:309 msgid "the `f?()` is basically a syntactic sugar for" msgstr "`f?()` 基本上是一个语法糖,等价于" -#: ../../language/error-handling.md:138 +#: ../../language/error-handling.md:311 msgid "" "let res = try {\n" " Ok(div!(10, 0))\n" @@ -257,7 +689,7 @@ msgid "" "}\n" msgstr "" -#: ../../language/error-handling.md:146 +#: ../../language/error-handling.md:319 msgid "" "Note the difference between `T?` and `f?(...)`: `T` is a type and `T?` is" " equivalent to `Option[T]` whereas `f?(...)` is a call to an error-able " @@ -266,13 +698,13 @@ msgstr "" "注意 `T?` 和 `f?(...)` 之间的区别:`T` 是一个类型,`T?` 等价于 `Option[T]`,而 `f?(...)` " "是对可出错函数 `f` 的调用。" -#: ../../language/error-handling.md:150 +#: ../../language/error-handling.md:323 msgid "" "Besides pattern matching, `Result` provides some useful methods to deal " "with possible error:" msgstr "除了模式匹配,`Result` 还提供了一些有用的方法来处理可能的错误:" -#: ../../language/error-handling.md:152 +#: ../../language/error-handling.md:325 msgid "" "let res1: Result[Int, String] = Err(\"error\")\n" "let value = res1.or(0) // 0\n" @@ -281,21 +713,21 @@ msgid "" "let value = res2.unwrap() // 42\n" msgstr "" -#: ../../language/error-handling.md:160 +#: ../../language/error-handling.md:333 msgid "" "`or` returns the value if the result is `Ok` or a default value if it is " "`Err`" msgstr "`or` 如果结果是 `Ok`,则返回值,如果是 `Err`,则返回默认值" -#: ../../language/error-handling.md:161 +#: ../../language/error-handling.md:334 msgid "`unwrap` panics if the result is `Err` and return the value if it is `Ok`" msgstr "`unwrap` 如果结果是 `Err`,则会崩溃,如果是 `Ok`,则返回值" -#: ../../language/error-handling.md:163 +#: ../../language/error-handling.md:336 msgid "Mapping values" msgstr "映射值" -#: ../../language/error-handling.md:165 +#: ../../language/error-handling.md:338 msgid "" "let res1: Result[Int, String] = Ok(42)\n" "let new_result = res1.map(fn(x) { x + 1 }) // Ok(43)\n" @@ -304,17 +736,17 @@ msgid "" "let new_result = res2.map_err(fn(x) { x + \"!\" }) // Err(\"error!\")\n" msgstr "" -#: ../../language/error-handling.md:173 +#: ../../language/error-handling.md:346 msgid "" "`map` applies a function to the value within, except it doesn't nothing " "if result is `Err`." msgstr "`map` 将函数应用于内部的值;如果结果是 `Err`,则不执行任何操作。" -#: ../../language/error-handling.md:174 +#: ../../language/error-handling.md:347 msgid "`map_error` does the opposite." msgstr "`map_error` 则相反。" -#: ../../language/error-handling.md:176 +#: ../../language/error-handling.md:349 msgid "" "Unlike some languages, MoonBit treats error-able and nullable value " "differently. Although one might treat them analogously, as an `Err` " @@ -324,11 +756,11 @@ msgstr "" "与一些语言不同,MoonBit 对可出错值和可空值进行了区分。尽管有些人可能将它们类比对待,因为一个不包含值的 `Err` 对象就像 " "`null`。MoonBit 知道这一点。" -#: ../../language/error-handling.md:178 +#: ../../language/error-handling.md:351 msgid "`to_option` converts a `Result` to `Option`." msgstr "`to_option` 将 `Result` 转换为 `Option`。" -#: ../../language/error-handling.md:180 +#: ../../language/error-handling.md:353 msgid "" "let res1: Result[Int, String] = Ok(42)\n" "let option = res1.to_option() // Some(42)\n" @@ -337,15 +769,15 @@ msgid "" "let option1 = res2.to_option() // None\n" msgstr "" -#: ../../language/error-handling.md:188 +#: ../../language/error-handling.md:361 msgid "Built-in error type and functions" msgstr "内置错误类型和相关函数" -#: ../../language/error-handling.md:190 +#: ../../language/error-handling.md:363 msgid "In MoonBit, `Error` is a generalized error type:" msgstr "在 MoonBit 中,`Error` 是一个通用的错误类型:" -#: ../../language/error-handling.md:192 +#: ../../language/error-handling.md:365 msgid "" "// These signatures are equivalent. They all raise Error.\n" "fn f() -> Unit! { .. }\n" @@ -365,19 +797,19 @@ msgid "" "}\n" msgstr "" -#: ../../language/error-handling.md:211 +#: ../../language/error-handling.md:384 msgid "" "Although the constructor `Err` expects a type of `Error`, we may still " "pass an error of type `DivisionByZeroError` to it." msgstr "尽管构造函数 `Err` 期望一个 `Error` 类型,我们仍然可以将 `DivisionByZeroError` 类型的错误传递给它。" -#: ../../language/error-handling.md:214 +#: ../../language/error-handling.md:387 msgid "" "But `Error` can't be constructed directly. It's meant to be passed " "around, not used directly:" msgstr "但是 `Error` 不能直接构造。它是用来传递的,而不是直接使用:" -#: ../../language/error-handling.md:216 +#: ../../language/error-handling.md:389 msgid "" "type! ArithmeticError\n" "\n" @@ -391,27 +823,27 @@ msgid "" "}\n" msgstr "" -#: ../../language/error-handling.md:229 +#: ../../language/error-handling.md:402 msgid "" "`Error` is typically used where concrete error type is not needed, or " "simply act as a catch-all for all kinds of sub-errors." msgstr "`Error` 通常用于不需要具体错误类型的情况,或者简单地用来捕获所有的子错误。" -#: ../../language/error-handling.md:232 +#: ../../language/error-handling.md:405 msgid "" "As `Error` includes multiple error types, partial matching is not allowed" " here. We have to do exhaustive matching by providing a catch-" "all/wildcard case `_`." msgstr "由于 `Error` 包含多种错误类型,这里不允许部分匹配。我们必须通过提供一个通配符 `_` 来进行兜底匹配。" -#: ../../language/error-handling.md:234 +#: ../../language/error-handling.md:407 msgid "" "We usually use the builtin `Failure` error type for a generalized error, " "and by generalized we mean using it for trivial errors that doesn't need " "a new error type." msgstr "我们通常使用内置的 `Failure` 错误类型来表示通用错误:通用意味着它用于不值得单独定义类型的错误。" -#: ../../language/error-handling.md:237 +#: ../../language/error-handling.md:410 msgid "" "fn div_trivial(x : Int, y : Int) -> Int!Failure {\n" " if y == 0 {\n" @@ -421,28 +853,28 @@ msgid "" "}\n" msgstr "" -#: ../../language/error-handling.md:246 +#: ../../language/error-handling.md:419 msgid "" "Besides using the constructor directly, the function `fail!` provides a " "shorthand to construct a `Failure`. And if we take a look at the source " "code:" msgstr "除了直接使用构造函数,函数 `fail!` 提供了一个快捷方式来构造 `Failure`。如果我们查看源代码:" -#: ../../language/error-handling.md:249 +#: ../../language/error-handling.md:422 msgid "" "pub fn fail[T](msg : String, ~loc : SourceLoc = _) -> T!Failure {\n" " raise Failure(\"FAILED: \\{loc} \\{msg}\")\n" "}\n" msgstr "" -#: ../../language/error-handling.md:255 +#: ../../language/error-handling.md:428 msgid "" "We can see that `fail` is merely a constructor with a pre-defined output " "template for showing both the error and the source location. In practice," " `fail!` is always preferred over `Failure`." msgstr "我们可以看到 `fail` 只是一个带有预定义输出模板的构造函数,用于显示错误和源位置。在实践中,`fail!` 总是比 `Failure`更常用。" -#: ../../language/error-handling.md:259 +#: ../../language/error-handling.md:432 msgid "" "Other functions used to break control flow are `abort` and `panic`. They " "are equivalent. An `panic` at any place will manually crash the program " @@ -457,161 +889,184 @@ msgstr "" #: ../../language/ffi-and-wasm-host.md:3 msgid "" +"What we've introduced is about describing pure computation. In reality, " +"you'll need to interact with the real world. However, the \"world\" is " +"different for each backend (C, JS, Wasm, WasmGC) and is sometimes based " +"on runtime ([Wasmtime](https://wasmtime.dev/), Deno, Browser, etc.)." +msgstr "" + +#: ../../language/ffi-and-wasm-host.md:7 +msgid "" "You can use foreign function in MoonBit through FFI to interact with the " "hosting runtime when embedded inside the browser or command line " "applications through [Wasmtime](https://wasmtime.dev/) or similar " "projects." msgstr "" -#: ../../language/ffi-and-wasm-host.md:5 -msgid "" -"⚠ Warning: MoonBit is still in early stage, so the content may be " -"outdated." +#: ../../language/ffi-and-wasm-host.md:9 +msgid "Init function" msgstr "" -#: ../../language/ffi-and-wasm-host.md:7 -msgid "FFI" +#: ../../language/ffi-and-wasm-host.md:11 +msgid "" +"For WebAssembly backend, it is compiled as [start " +"function](https://webassembly.github.io/spec/core/syntax/modules.html" +"#start-function), meaning that it will be executed **before** the " +"instance is available, and the FFIs that relies on the instance's " +"exportations can not be used at this stage; for JavaScript backend, it " +"means that it will be executed during the importation stage." msgstr "" -#: ../../language/ffi-and-wasm-host.md:9 +#: ../../language/ffi-and-wasm-host.md:14 msgid "Declare Foreign Reference" msgstr "" -#: ../../language/ffi-and-wasm-host.md:11 +#: ../../language/ffi-and-wasm-host.md:16 msgid "You can declare a foreign reference type like this:" msgstr "" -#: ../../language/ffi-and-wasm-host.md:13 +#: ../../language/ffi-and-wasm-host.md:18 msgid "type Canvas_ctx\n" msgstr "" -#: ../../language/ffi-and-wasm-host.md:17 +#: ../../language/ffi-and-wasm-host.md:22 msgid "" "This will be a type that represents a reference to a foreign object, a " "`CanvasRenderingContext2D` object held by the hosting JavaScript runtime " "in this example." msgstr "" -#: ../../language/ffi-and-wasm-host.md:19 +#: ../../language/ffi-and-wasm-host.md:24 msgid "Declare Foreign Function" msgstr "" -#: ../../language/ffi-and-wasm-host.md:21 +#: ../../language/ffi-and-wasm-host.md:26 +msgid "" +"You can either import a function with module name and function name or " +"writing an inline function." +msgstr "" + +#: ../../language/ffi-and-wasm-host.md:28 +msgid "Import function" +msgstr "" + +#: ../../language/ffi-and-wasm-host.md:30 msgid "You can declare a foreign function like this:" msgstr "" -#: ../../language/ffi-and-wasm-host.md:23 +#: ../../language/ffi-and-wasm-host.md:32 msgid "fn cos(d : Double) -> Double = \"Math\" \"cos\"\n" msgstr "" -#: ../../language/ffi-and-wasm-host.md:27 +#: ../../language/ffi-and-wasm-host.md:36 msgid "" "It's similar to a normal function definition except that the function " "body is replaced with two strings." msgstr "" -#: ../../language/ffi-and-wasm-host.md:29 +#: ../../language/ffi-and-wasm-host.md:38 msgid "" -"For WasmGC backend, these two strings are used to identify the specific " -"function from a Wasm import object, the first string is the module name, " -"and the second string is the function name. For JS backend, these two " -"strings are used to call a static function in the global namespace. The " -"example above becomes similar to `const cos = (d) => Math.cos(d)`." +"For Wasm(GC) backend, these two strings are used to identify the specific" +" function from a Wasm import object, the first string is the module name," +" and the second string is the function name." msgstr "" -#: ../../language/ffi-and-wasm-host.md:31 +#: ../../language/ffi-and-wasm-host.md:40 +msgid "" +"For JS backend, these two strings are used to call a static function in " +"the global namespace. The example above becomes similar to `const cos = " +"(d) => Math.cos(d)`." +msgstr "" + +#: ../../language/ffi-and-wasm-host.md:42 +msgid "Inline function" +msgstr "" + +#: ../../language/ffi-and-wasm-host.md:44 msgid "" "You can also declare inline functions where the function body is replaced" " with one string." msgstr "" -#: ../../language/ffi-and-wasm-host.md:33 +#: ../../language/ffi-and-wasm-host.md:46 msgid "" -"For WasmGC backend, you may declare it as a Wasm function without name " +"For Wasm(GC) backend, you may declare it as a Wasm function without name " "(which will be generated afterwards):" msgstr "" -#: ../../language/ffi-and-wasm-host.md:35 +#: ../../language/ffi-and-wasm-host.md:48 msgid "" "extern \"wasm\" fn abs(d : Double) -> Double =\n" " #|(func (param f64) (result f64))\n" msgstr "" -#: ../../language/ffi-and-wasm-host.md:40 +#: ../../language/ffi-and-wasm-host.md:53 msgid "and for JS backend, you may declare it as a lambda expression:" msgstr "" -#: ../../language/ffi-and-wasm-host.md:42 +#: ../../language/ffi-and-wasm-host.md:55 msgid "" "extern \"js\" fn abs(d : Double) -> Double =\n" " #|(d) => Math.abs(d)\n" msgstr "" -#: ../../language/ffi-and-wasm-host.md:47 +#: ../../language/ffi-and-wasm-host.md:60 msgid "After declaration, you can use foreign functions like regular functions." msgstr "" -#: ../../language/ffi-and-wasm-host.md:49 +#: ../../language/ffi-and-wasm-host.md:62 msgid "" "For multi-backend project, you may implement backend specific code in the" -" files that ends with `.wasm.mbt` `.wasm-gc.mbt` and `.js.mbt`." +" files that ends with `.wasm.mbt` `.wasm-gc.mbt` and `.js.mbt`. Check out" +" [link options]() for details." msgstr "" -#: ../../language/ffi-and-wasm-host.md:51 +#: ../../language/ffi-and-wasm-host.md:64 msgid "" "You may also declare a foreign function that will be invoked upon a " "foreign object by using the foreign reference type like this:" msgstr "" -#: ../../language/ffi-and-wasm-host.md:53 +#: ../../language/ffi-and-wasm-host.md:66 msgid "fn begin_path(self: Canvas_ctx) = \"canvas\" \"begin_path\"\n" msgstr "" -#: ../../language/ffi-and-wasm-host.md:57 +#: ../../language/ffi-and-wasm-host.md:70 msgid "" "and apply it to a previously owned reference normally such as " "`context.begin_path()`." msgstr "" -#: ../../language/ffi-and-wasm-host.md:59 -msgid "Exported functions" +#: ../../language/ffi-and-wasm-host.md:72 +msgid "Export functions" msgstr "" -#: ../../language/ffi-and-wasm-host.md:61 +#: ../../language/ffi-and-wasm-host.md:74 msgid "" "Functions that are not methods nor polymorphic functions can be exported " "if they are public and if the link configuration appears in the " "`moon.pkg.json` of the package:" msgstr "" -#: ../../language/ffi-and-wasm-host.md:63 +#: ../../language/ffi-and-wasm-host.md:76 msgid "" "{\n" " \"link\": {\n" " \"wasm\": {\n" -" \"exports\": [\n" -" \"add\",\n" -" \"fib:test\"\n" -" ]\n" +" \"exports\": [ \"add\", \"fib:test\" ]\n" " },\n" " \"wasm-gc\": {\n" -" \"exports\": [\n" -" \"add\",\n" -" \"fib:test\"\n" -" ]\n" +" \"exports\": [ \"add\", \"fib:test\" ]\n" " },\n" " \"js\": {\n" -" \"exports\": [\n" -" \"add\",\n" -" \"fib:test\"\n" -" ],\n" +" \"exports\": [ \"add\", \"fib:test\" ],\n" " \"format\": \"esm\"\n" " }\n" " }\n" "}\n" msgstr "" -#: ../../language/ffi-and-wasm-host.md:89 +#: ../../language/ffi-and-wasm-host.md:93 msgid "" "Each backend has a separate definition. For JS backend, a `format` option" " is used to specify whether the generated JavaScript file should be " @@ -619,44 +1074,38 @@ msgid "" "immediately invoked function expression (`iife`)." msgstr "" -#: ../../language/ffi-and-wasm-host.md:91 +#: ../../language/ffi-and-wasm-host.md:95 msgid "" "The example above will export function `add` and `fib`, and the function " "`fib` will be exported with the name of `test`." msgstr "" -#: ../../language/ffi-and-wasm-host.md:93 -msgid "" -"For WasmGC backend, the `_start` function should always be called to " -"initialize all the global instances defined in MoonBit program." -msgstr "" - -#: ../../language/ffi-and-wasm-host.md:95 +#: ../../language/ffi-and-wasm-host.md:97 msgid "Use compiled Wasm" msgstr "" -#: ../../language/ffi-and-wasm-host.md:97 +#: ../../language/ffi-and-wasm-host.md:99 msgid "" "To use the compiled Wasm, you need to initialize the Wasm module with the" " host functions so as to meet the needs of the foreign functions, and " "then use the exported functions provided by the Wasm module." msgstr "" -#: ../../language/ffi-and-wasm-host.md:99 +#: ../../language/ffi-and-wasm-host.md:101 msgid "Provide host functions" msgstr "" -#: ../../language/ffi-and-wasm-host.md:101 +#: ../../language/ffi-and-wasm-host.md:103 msgid "" "To use the compiled Wasm, you must provide **All** declared foreign " "functions in Wasm import object." msgstr "" -#: ../../language/ffi-and-wasm-host.md:103 +#: ../../language/ffi-and-wasm-host.md:105 msgid "For example, to use wasm compiled from above code snippet in JavaScript:" msgstr "" -#: ../../language/ffi-and-wasm-host.md:105 +#: ../../language/ffi-and-wasm-host.md:107 msgid "" "WebAssembly.instantiateStreaming(fetch(\"xxx.wasm\"), {\n" " Math: {\n" @@ -665,24 +1114,24 @@ msgid "" "});\n" msgstr "" -#: ../../language/ffi-and-wasm-host.md:113 +#: ../../language/ffi-and-wasm-host.md:115 msgid "" "Check out the documentation such as [MDN](https://developer.mozilla.org" "/en-US/docs/WebAssembly) or the manual of runtime that you're using to " "embed the Wasm." msgstr "" -#: ../../language/ffi-and-wasm-host.md:115 +#: ../../language/ffi-and-wasm-host.md:117 msgid "Example: Smiling face" msgstr "" -#: ../../language/ffi-and-wasm-host.md:117 +#: ../../language/ffi-and-wasm-host.md:119 msgid "" "Let's walk through a full example to draw a smiling face using Canvas API" " in MoonBit. Suppose you created a new project with `moon new draw`" msgstr "" -#: ../../language/ffi-and-wasm-host.md:119 +#: ../../language/ffi-and-wasm-host.md:121 msgid "" "// We first declare a type representing the context of canvas\n" "type Canvas_ctx\n" @@ -718,7 +1167,7 @@ msgid "" "}\n" msgstr "" -#: ../../language/ffi-and-wasm-host.md:152 +#: ../../language/ffi-and-wasm-host.md:154 msgid "" "{\n" " \"link\": {\n" @@ -732,18 +1181,18 @@ msgid "" "}\n" msgstr "" -#: ../../language/ffi-and-wasm-host.md:165 +#: ../../language/ffi-and-wasm-host.md:167 msgid "" "Build the project using `moon build`. We recommend using Wasm with GC " "integration whenever possible (which is the default). If the environment " "does not support the GC feature, use the `--target wasm` option instead." msgstr "" -#: ../../language/ffi-and-wasm-host.md:167 +#: ../../language/ffi-and-wasm-host.md:169 msgid "We now can use it from JavaScript." msgstr "" -#: ../../language/ffi-and-wasm-host.md:169 +#: ../../language/ffi-and-wasm-host.md:171 msgid "" "\n" " \n" @@ -774,7 +1223,7 @@ msgid "" "\n" msgstr "" -#: ../../language/ffi-and-wasm-host.md:198 +#: ../../language/ffi-and-wasm-host.md:200 msgid "" "For import object, we need to provide all the FFI used in the previously " "defined program: the canvas rendering API, the math API and finally, an " @@ -782,7 +1231,7 @@ msgid "" "function." msgstr "" -#: ../../language/ffi-and-wasm-host.md:200 +#: ../../language/ffi-and-wasm-host.md:202 msgid "" "As of the canvas rendering API and the math API, we can use the following" " code to convert the methods of objects into function calls that accept " @@ -790,7 +1239,7 @@ msgid "" " objects into functions that returns the value:" msgstr "" -#: ../../language/ffi-and-wasm-host.md:202 +#: ../../language/ffi-and-wasm-host.md:204 msgid "" "function prototype_to_ffi(prototype) {\n" " return Object.fromEntries(\n" @@ -814,14 +1263,14 @@ msgid "" "}\n" msgstr "" -#: ../../language/ffi-and-wasm-host.md:224 +#: ../../language/ffi-and-wasm-host.md:226 msgid "" "As of the printing service, we can provide the following closure so that " "it buffers the bytes of string until it needs to be logged to the " "console:" msgstr "" -#: ../../language/ffi-and-wasm-host.md:226 +#: ../../language/ffi-and-wasm-host.md:228 msgid "" "const [log, flush] = (() => {\n" " var buffer = [];\n" @@ -858,11 +1307,11 @@ msgid "" ");\n" msgstr "" -#: ../../language/ffi-and-wasm-host.md:260 +#: ../../language/ffi-and-wasm-host.md:262 msgid "Now, we put them together, so this is our final complete `index.html`:" msgstr "" -#: ../../language/ffi-and-wasm-host.md:262 +#: ../../language/ffi-and-wasm-host.md:264 msgid "" "\n" "\n" @@ -931,1892 +1380,1868 @@ msgid "" "\n" msgstr "" -#: ../../language/ffi-and-wasm-host.md:328 +#: ../../language/ffi-and-wasm-host.md:330 msgid "" "Make sure that `draw.wasm` and `index.html` are in the same folder, then " "start a http server at this folder. For example, using Python:" msgstr "" -#: ../../language/ffi-and-wasm-host.md:330 +#: ../../language/ffi-and-wasm-host.md:332 msgid "python3 -m http.server 8080\n" msgstr "" -#: ../../language/ffi-and-wasm-host.md:334 +#: ../../language/ffi-and-wasm-host.md:336 msgid "" "Goto [http://localhost:8080](http://localhost:8080) in your browser, " "there should be a smile face on the screen and an output on the console:" msgstr "" -#: ../../language/ffi-and-wasm-host.md:336 +#: ../../language/ffi-and-wasm-host.md:338 msgid "" "![A smile face webpage with browser devtools " "open](../imgs/smile_face_with_log.png)" msgstr "" -#: ../../language/ffi-and-wasm-host.md:336 +#: ../../language/ffi-and-wasm-host.md:338 msgid "A smile face webpage with browser devtools open" msgstr "" -#: ../../language/index.md:9 -msgid "Contents:" -msgstr "" - -#: ../../language/index.md:1 -msgid "Language" +#: ../../language/fundamentals.md:1 +msgid "Fundamentals" msgstr "" -#: ../../language/index.md:3 -msgid "Here are the topics about the programming syntax." +#: ../../language/fundamentals.md:3 +msgid "Built-in Data Structures" msgstr "" -#: ../../language/index.md:5 -msgid "" -"[MoonBit](./language.md): almost everything you need to know about the " -"MoonBit grammar." +#: ../../language/fundamentals.md:5 +msgid "Boolean" msgstr "" -#: ../../language/index.md:6 +#: ../../language/fundamentals.md:7 msgid "" -"[Error handling](./error-handling.md): the error handling mechanism in " -"MoonBit." +"MoonBit has a built-in boolean type, which has two values: `true` and " +"`false`. The boolean type is used in conditional expressions and control " +"structures." msgstr "" -#: ../../language/index.md:7 +#: ../../language/fundamentals.md:9 msgid "" -"[Foreign Function Interface](./ffi-and-wasm-host.md): how MoonBit " -"interacts with the real world using different backends." -msgstr "" - -#: ../../language/language.md:1 -msgid "MoonBit" +"let a = true\n" +"let b = false\n" +"let c = a && b\n" +"let d = a || b\n" +"let e = not(a)\n" msgstr "" -#: ../../language/language.md:3 -msgid "" -"MoonBit is an end-to-end programming language toolchain for cloud and " -"edge computing using WebAssembly. The IDE environment is available at " -"[https://try.moonbitlang.com](https://try.moonbitlang.com) without any " -"installation; it does not rely on any server either." +#: ../../language/fundamentals.md:16 +msgid "Number" msgstr "" -#: ../../language/language.md:5 -msgid "Status and aimed timeline" +#: ../../language/fundamentals.md:18 +msgid "MoonBit have integer type and floating point type:" msgstr "" -#: ../../language/language.md:7 -msgid "" -"MoonBit is currently in beta-preview. We expect to reach beta in " -"2024/11/22, and 1.0 in 2025." +#: ../../language/fundamentals.md:9 +msgid "type" msgstr "" -#: ../../language/language.md:9 -msgid "" -"When MoonBit reaches beta, it means any backwards-incompatible changes " -"will be seriously evaluated and MoonBit _can_ be used in production(very " -"rare compiler bugs). MoonBit is developed by a talented full time team " -"who had extensive experience in building language toolchains, so we will " -"grow much faster than the typical language ecosystem, you won't wait long" -" to use MoonBit in your production." +#: ../../language/fundamentals.md:9 ../../language/fundamentals.md:115 +msgid "description" msgstr "" -#: ../../language/language.md:11 -msgid "Main advantages" +#: ../../language/fundamentals.md:9 +msgid "example" msgstr "" -#: ../../language/language.md:13 -msgid "Generate significantly smaller WASM output than any existing solutions." +#: ../../language/fundamentals.md:9 +msgid "`Int`" msgstr "" -#: ../../language/language.md:14 -msgid "Much faster runtime performance." +#: ../../language/fundamentals.md:9 +msgid "32-bit signed integer" msgstr "" -#: ../../language/language.md:15 -msgid "State of the art compile-time performance." +#: ../../language/fundamentals.md:9 +msgid "`42`" msgstr "" -#: ../../language/language.md:16 -msgid "Simple but practical, data-oriented language design." +#: ../../language/fundamentals.md:9 +msgid "`Int64`" msgstr "" -#: ../../language/language.md:18 -msgid "Overview" +#: ../../language/fundamentals.md:9 +msgid "64-bit signed integer" msgstr "" -#: ../../language/language.md:20 -msgid "" -"A MoonBit program consists of type definitions, function definitions, and" -" variable bindings." +#: ../../language/fundamentals.md:9 +msgid "`1000L`" msgstr "" -#: ../../language/language.md:22 -msgid "Program entrance" +#: ../../language/fundamentals.md:9 +msgid "`UInt`" msgstr "" -#: ../../language/language.md:24 -msgid "" -"There is a specialized function called `init` function. The `init` " -"function is special in two aspects:" +#: ../../language/fundamentals.md:9 +msgid "32-bit unsigned integer" msgstr "" -#: ../../language/language.md:26 -msgid "There can be multiple `init` functions in the same package." +#: ../../language/fundamentals.md:9 +msgid "`14U`" msgstr "" -#: ../../language/language.md:27 -msgid "" -"An `init` function can't be explicitly called or referred to by other " -"functions. Instead, all `init` functions will be implicitly called when " -"initializing a package. Therefore, `init` functions should only consist " -"of statements." +#: ../../language/fundamentals.md:9 +msgid "`UInt64`" msgstr "" -#: ../../language/language.md:29 -msgid "" -"fn init {\n" -" let x = 1\n" -" println(x)\n" -"}\n" +#: ../../language/fundamentals.md:9 +msgid "64-bit unsigned integer" msgstr "" -#: ../../language/language.md:35 -msgid "" -"For WebAssembly backend, it means that it will be executed **before** the" -" instance is available, meaning that the FFIs that relies on the " -"instance's exportations can not be used at this stage; for JavaScript " -"backend, it means that it will be executed during the importation stage." +#: ../../language/fundamentals.md:9 +msgid "`14UL`" msgstr "" -#: ../../language/language.md:38 -msgid "" -"There is another specialized function called `main` function. The `main` " -"function is the main entrance of the program, and it will be executed " -"after the initialization stage." +#: ../../language/fundamentals.md:9 +msgid "`Double`" msgstr "" -#: ../../language/language.md:40 -msgid "" -"fn main {\n" -" let x = 2\n" -" println(x)\n" -"}\n" +#: ../../language/fundamentals.md:9 +msgid "64-bit floating point, defined by IEEE754" msgstr "" -#: ../../language/language.md:46 -msgid "The previous two code snippets will print the following at runtime:" +#: ../../language/fundamentals.md:9 +msgid "`3.14`" msgstr "" -#: ../../language/language.md:48 -msgid "" -"1\n" -"2\n" +#: ../../language/fundamentals.md:9 +msgid "`Float`" msgstr "" -#: ../../language/language.md:54 -msgid "" -"Only packages that are `main` packages can define such `main` function. " -"Check out [build system tutorial](/toolchain/moon/tutorial) for detail." +#: ../../language/fundamentals.md:9 +msgid "32-bit floating point" msgstr "" -#: ../../language/language.md:56 -msgid "moon.pkg.json" +#: ../../language/fundamentals.md:9 +msgid "`(3.14 : Float)`" msgstr "" -#: ../../language/language.md:56 -msgid "" -"{\n" -" \"is-main\": true\n" -"}" +#: ../../language/fundamentals.md:9 +msgid "`BigInt`" msgstr "" -#: ../../language/language.md:61 -msgid "" -"The two functions above need to drop the parameter list and the return " -"type." +#: ../../language/fundamentals.md:9 +msgid "represents numeric values larger than other types" msgstr "" -#: ../../language/language.md:63 -msgid "Expressions and Statements" +#: ../../language/fundamentals.md:9 +msgid "`10000000000000000000000N`" msgstr "" -#: ../../language/language.md:65 +#: ../../language/fundamentals.md:30 msgid "" -"MoonBit distinguishes between statements and expressions. In a function " -"body, only the last clause should be an expression, which serves as a " -"return value. For example:" +"MoonBit also supports numeric literals, including decimal, binary, octal," +" and hexadecimal numbers." msgstr "" -#: ../../language/language.md:67 +#: ../../language/fundamentals.md:32 msgid "" -"fn foo() -> Int {\n" -" let x = 1\n" -" x + 1\n" -"}\n" -"\n" -"fn bar() -> Int {\n" -" let x = 1\n" -" // x + 1 // fail\n" -" x + 2\n" -"}\n" +"To improve readability, you may place underscores in the middle of " +"numeric literals such as `1_000_000`. Note that underscores can be placed" +" anywhere within a number, not just every three digits." msgstr "" -#: ../../language/language.md:73 -msgid "Expressions include:" +#: ../../language/fundamentals.md:34 +msgid "Decimal numbers can have underscore between the numbers." msgstr "" -#: ../../language/language.md:75 +#: ../../language/fundamentals.md:36 msgid "" -"Value literals (e.g. Boolean values, numbers, characters, strings, " -"arrays, tuples, structs)" -msgstr "" - -#: ../../language/language.md:76 -msgid "Arithmetical, logical, or comparison operations" +"By default, an int literal is signed 32-bit number. For unsigned numbers," +" a postfix `U` is needed; for 64-bit numbers, a postfix `L` is needed." msgstr "" -#: ../../language/language.md:77 +#: ../../language/fundamentals.md:38 msgid "" -"Accesses to array elements (e.g. `a[0]`) or struct fields (e.g `r.x`) or " -"tuple components (e.g. `t.0`)" -msgstr "" - -#: ../../language/language.md:78 -msgid "Variables and (capitalized) enum constructors" -msgstr "" - -#: ../../language/language.md:79 -msgid "Anonymous local function definitions" -msgstr "" - -#: ../../language/language.md:80 -msgid "`match` and `if` expressions" -msgstr "" - -#: ../../language/language.md:82 -msgid "Statements include:" -msgstr "" - -#: ../../language/language.md:84 -msgid "Named local function definitions" -msgstr "" - -#: ../../language/language.md:85 -msgid "Local variable bindings" -msgstr "" - -#: ../../language/language.md:86 -msgid "Assignments" -msgstr "" - -#: ../../language/language.md:87 -msgid "`return` statements" -msgstr "" - -#: ../../language/language.md:88 -msgid "Any expression whose return type is `Unit`" -msgstr "" - -#: ../../language/language.md:90 -msgid "Functions" +"let a = 1234\n" +"let b : Int = 1_000_000 + a\n" +"let unsigned_num : UInt = 4_294_967_295U\n" +"let large_num : Int64 = 9_223_372_036_854_775_807L\n" +"let unsigned_large_num : UInt64 = 18_446_744_073_709_551_615UL\n" msgstr "" -#: ../../language/language.md:92 +#: ../../language/fundamentals.md:45 msgid "" -"Functions take arguments and produce a result. In MoonBit, functions are " -"first-class, which means that functions can be arguments or return values" -" of other functions. MoonBit's naming convention requires that function " -"names should not begin with uppercase letters (A-Z). Compare for " -"constructors in the `enum` section below." +"A binary number has a leading zero followed by a letter \"B\", i.e. " +"`0b`/`0B`. Note that the digits after `0b`/`0B` must be `0` or `1`." msgstr "" -#: ../../language/language.md:94 -msgid "Top-Level Functions" +#: ../../language/fundamentals.md:48 +msgid "" +"let bin = 0b110010\n" +"let another_bin = 0B110010\n" msgstr "" -#: ../../language/language.md:96 +#: ../../language/fundamentals.md:55 msgid "" -"Functions can be defined as top-level or local. We can use the `fn` " -"keyword to define a top-level function that sums three integers and " -"returns the result, as follows:" +"An octal number has a leading zero followed by a letter \"O\", i.e. " +"`0o`/`0O`. Note that the digits after `0o`/`0O` must be in the range from" +" `0` through `7`:" msgstr "" -#: ../../language/language.md:98 +#: ../../language/fundamentals.md:58 msgid "" -"fn add3(x : Int, y : Int, z : Int) -> Int {\n" -" x + y + z\n" -"}\n" +"let octal = 0o1234\n" +"let another_octal = 0O1234\n" msgstr "" -#: ../../language/language.md:104 +#: ../../language/fundamentals.md:65 msgid "" -"Note that the arguments and return value of top-level functions require " -"explicit type annotations." +"A hexadecimal number has a leading zero followed by a letter \"X\", i.e. " +"`0x`/`0X`. Note that the digits after the `0x`/`0X` must be in the range " +"`0123456789ABCDEF`." msgstr "" -#: ../../language/language.md:106 -msgid "Local Functions" +#: ../../language/fundamentals.md:68 +msgid "" +"let hex = 0XA\n" +"let another_hex = 0xA_B_C\n" msgstr "" -#: ../../language/language.md:108 +#: ../../language/fundamentals.md:75 msgid "" -"Local functions can be named or anonymous. Type annotations can be " -"omitted for local function definitions: they can be automatically " -"inferred in most cases. For example:" +"A floating-point number literal is 64-bit floating-point number. To " +"define a float, type annotation is needed." msgstr "" -#: ../../language/language.md:110 +#: ../../language/fundamentals.md:77 msgid "" -"fn local_1() -> Int {\n" -" fn inc(x) { // named as `inc`\n" -" x + 1\n" -" }\n" -" // anonymous, instantly appplied to integer literal 6\n" -" (fn(x) { x + inc(2) })(6)\n" -"}\n" -"\n" -"test {\n" -" assert_eq!(local_1(), 9)\n" -"}\n" +"let double = 3.14 // Double\n" +"let float : Float = 3.14\n" +"let float2 = (3.14 : Float)\n" msgstr "" -#: ../../language/language.md:116 +#: ../../language/fundamentals.md:84 msgid "" -"Functions, whether named or anonymous, are _lexical closures_: any " -"identifiers without a local binding must refer to bindings from a " -"surrounding lexical scope. For example:" +"A 64-bit floating-point number can also be defined using hexadecimal " +"format:" msgstr "" -#: ../../language/language.md:118 -msgid "" -"let global_y = 3\n" -"\n" -"fn local_2(x : Int) -> (Int, Int) {\n" -" fn inc() {\n" -" x + 1\n" -" }\n" -"\n" -" fn four() {\n" -" global_y + 1\n" -" }\n" -"\n" -" (inc(), four())\n" -"}\n" -"\n" -"test {\n" -" assert_eq!(local_2(3), (4, 4))\n" -"}\n" +#: ../../language/fundamentals.md:86 +msgid "let hex_double = 0x1.2P3 // (1.0 + 2 / 16) * 2^(+3) == 9\n" msgstr "" -#: ../../language/language.md:124 -msgid "Function Applications" +#: ../../language/fundamentals.md:93 +msgid "Overloaded literal" msgstr "" -#: ../../language/language.md:126 -msgid "A function can be applied to a list of arguments in parentheses:" +#: ../../language/fundamentals.md:95 +msgid "" +"When the expected type is known, MoonBit can automatically overload " +"literal, and there is no need to specify the type of number via letter " +"postfix:" msgstr "" -#: ../../language/language.md:128 -msgid "add3(1, 2, 7)\n" +#: ../../language/fundamentals.md:97 +msgid "" +"let int : Int = 42\n" +"let uint : UInt = 42\n" +"let int64 : Int64 = 42\n" +"let double : Double = 42\n" +"let float : Float = 42\n" +"let bigint : BigInt = 42\n" msgstr "" -#: ../../language/language.md:132 +#: ../../language/fundamentals.md:104 +msgid "String" +msgstr "" + +#: ../../language/fundamentals.md:106 msgid "" -"This works whether `add3` is a function defined with a name (as in the " -"previous example), or a variable bound to a function value, as shown " -"below:" +"`String` holds a sequence of UTF-16 code units. You can use double quotes" +" to create a string, or use `#|` to write a multi-line string." msgstr "" -#: ../../language/language.md:134 +#: ../../language/fundamentals.md:108 msgid "" -"test {\n" -" let add3 = fn(x, y, z) { x + y + z }\n" -" assert_eq!(add3(1, 2, 7), 10)\n" -"}\n" +"let a = \"兔rabbit\"\n" +"println(a[0])\n" +"println(a[1])\n" +"let b =\n" +" #| Hello\n" +" #| MoonBit\\n\n" +" #|\n" +"println(b)\n" msgstr "" -#: ../../language/language.md:140 +#: ../../language/fundamentals.md:115 msgid "" -"The expression `add3(1, 2, 7)` returns `10`. Any expression that " -"evaluates to a function value is applicable:" +"'兔'\n" +"'r'\n" +" Hello\n" +" MoonBit\\n\n" +"\n" msgstr "" -#: ../../language/language.md:142 +#: ../../language/fundamentals.md:119 msgid "" -"test {\n" -" let f = fn(x) { x + 1 }\n" -" let g = fn(x) { x + 2 }\n" -" let w = (if true { f } else { g })(3)\n" -" assert_eq!(w, 4)\n" -"}\n" +"In double quotes string, a backslash followed by certain special " +"characters forms an escape sequence:" msgstr "" -#: ../../language/language.md:149 -msgid "Labelled arguments" +#: ../../language/fundamentals.md:115 +msgid "escape sequences" msgstr "" -#: ../../language/language.md:151 -msgid "" -"Functions can declare labelled argument with the syntax `label~ : Type`. " -"`label` will also serve as parameter name inside function body:" +#: ../../language/fundamentals.md:115 +msgid "`\\n`,`\\r`,`\\t`,`\\b`" msgstr "" -#: ../../language/language.md:153 -msgid "" -"fn labelled_1(arg1~ : Int, arg2~ : Int) -> Int {\n" -" arg1 + arg2\n" -"}\n" +#: ../../language/fundamentals.md:115 +msgid "New line, Carriage return, Horizontal tab, Backspace" msgstr "" -#: ../../language/language.md:159 -msgid "" -"Labelled arguments can be supplied via the syntax `label=arg`. " -"`label=label` can be abbreviated as `label~`:" +#: ../../language/fundamentals.md:115 +msgid "`\\\\`" msgstr "" -#: ../../language/language.md:161 -msgid "" -"test {\n" -" let arg1 = 1\n" -" assert_eq!(labelled_1(arg2=2, arg1~), 3)\n" -"}\n" +#: ../../language/fundamentals.md:115 +msgid "Backslash" msgstr "" -#: ../../language/language.md:167 -msgid "" -"Labelled function can be supplied in any order. The evaluation order of " -"arguments is the same as the order of parameters in function declaration." +#: ../../language/fundamentals.md:115 +msgid "`\\x41`" msgstr "" -#: ../../language/language.md:169 -msgid "Optional arguments" +#: ../../language/fundamentals.md:115 +msgid "Hexadecimal escape sequence" msgstr "" -#: ../../language/language.md:171 -msgid "" -"A labelled argument can be made optional by supplying a default " -"expression with the syntax `label~ : Type = default_expr`. If this " -"argument is not supplied at call site, the default expression will be " -"used:" +#: ../../language/fundamentals.md:115 +msgid "`\\o102`" msgstr "" -#: ../../language/language.md:173 -msgid "" -"fn optional(opt~ : Int = 42) -> Int {\n" -" opt\n" -"}\n" -"\n" -"test {\n" -" assert_eq!(optional(), 42)\n" -" assert_eq!(optional(opt=0), 0)\n" -"}\n" +#: ../../language/fundamentals.md:115 +msgid "Octal escape sequence" msgstr "" -#: ../../language/language.md:179 -msgid "" -"The default expression will be evaluated every time it is used. And the " -"side effect in the default expression, if any, will also be triggered. " -"For example:" +#: ../../language/fundamentals.md:115 +msgid "`\\u5154`,`\\u{1F600}`" +msgstr "" + +#: ../../language/fundamentals.md:115 +msgid "Unicode escape sequence" msgstr "" -#: ../../language/language.md:181 +#: ../../language/fundamentals.md:129 msgid "" -"fn incr(counter~ : Ref[Int] = { val: 0 }) -> Ref[Int] {\n" -" counter.val = counter.val + 1\n" -" counter\n" -"}\n" -"\n" -"test {\n" -" inspect!(incr(), content=\"{val: 1}\")\n" -" inspect!(incr(), content=\"{val: 1}\")\n" -" let counter : Ref[Int] = { val: 0 }\n" -" inspect!(incr(counter~), content=\"{val: 1}\")\n" -" inspect!(incr(counter~), content=\"{val: 2}\")\n" -"}\n" +"MoonBit supports string interpolation. It enables you to substitute " +"variables within interpolated strings. This feature simplifies the " +"process of constructing dynamic strings by directly embedding variable " +"values into the text. Variables used for string interpolation must " +"support the `to_string` method." msgstr "" -#: ../../language/language.md:187 +#: ../../language/fundamentals.md:131 msgid "" -"If you want to share the result of default expression between different " -"function calls, you can lift the default expression to a toplevel `let` " -"declaration:" +"let x = 42\n" +"println(\"The answer is \\{x}\")\n" msgstr "" -#: ../../language/language.md:189 +#: ../../language/fundamentals.md:138 msgid "" -"let default_counter : Ref[Int] = { val: 0 }\n" -"\n" -"fn incr_2(counter~ : Ref[Int] = default_counter) -> Int {\n" -" counter.val = counter.val + 1\n" -" counter.val\n" -"}\n" -"\n" -"test {\n" -" assert_eq!(incr_2(), 1)\n" -" assert_eq!(incr_2(), 2)\n" -"}\n" +"Multi-line strings do not support interpolation by default, but you can " +"enable interpolation for a specific line by changing the leading `#|` to " +"`$|`:" msgstr "" -#: ../../language/language.md:195 +#: ../../language/fundamentals.md:140 msgid "" -"Default expression can depend on the value of previous arguments. For " -"example:" +"let lang = \"MoonBit\"\n" +"let str =\n" +" #| Hello\n" +" #| ---\n" +" $| \\{lang}\\n\n" +" #| ---\n" +"println(str)\n" msgstr "" -#: ../../language/language.md:197 +#: ../../language/fundamentals.md:147 msgid "" -"fn sub_array[X](\n" -" xs : Array[X],\n" -" offset~ : Int,\n" -" len~ : Int = xs.length() - offset\n" -") -> Array[X] {\n" -" xs[offset:offset + len].iter().to_array()\n" -"}\n" +" Hello\n" +" ---\n" +" MoonBit\n" "\n" -"test {\n" -" assert_eq!(sub_array([1, 2, 3], offset=1), [2, 3])\n" -" assert_eq!(sub_array([1, 2, 3], offset=1, len=1), [2])\n" -"}\n" +" ---\n" msgstr "" -#: ../../language/language.md:204 -msgid "Automatically insert `Some` when supplying optional arguments" +#: ../../language/fundamentals.md:151 +msgid "Char" msgstr "" -#: ../../language/language.md:206 -msgid "" -"It is quite often optional arguments have type `T?` with `None` as " -"default value. In this case, passing the argument explicitly requires " -"wrapping a `Some`, which is ugly:" +#: ../../language/fundamentals.md:153 +msgid "`Char` represents a Unicode code point." msgstr "" -#: ../../language/language.md:210 +#: ../../language/fundamentals.md:155 msgid "" -"fn ugly_constructor(width~ : Int? = None, height~ : Int? = None) -> Image" -" {\n" -" ...\n" -"}\n" -"\n" -"let img : Image = ugly_constructor(width=Some(1920), height=Some(1080))\n" +"let a : Char = 'A'\n" +"let b = '\\x41'\n" +"let c = '兔'\n" +"let zero = '\\u{30}'\n" +"let zero = '\\u0030'\n" +msgstr "" + +#: ../../language/fundamentals.md:162 +msgid "Byte(s)" msgstr "" -#: ../../language/language.md:216 +#: ../../language/fundamentals.md:164 msgid "" -"Fortunately, MoonBit provides a special kind of optional arguments to " -"solve this problem. Optional arguments declared with `label? : T` has " -"type `T?` and `None` as default value. When supplying this kind of " -"optional argument directly, MoonBit will automatically insert a `Some`:" +"A byte literal in MoonBit is either a single ASCII character or a single " +"escape enclosed in single quotes `'`, and preceded by the character `b`. " +"Byte literals are of type `Byte`. For example:" msgstr "" -#: ../../language/language.md:220 +#: ../../language/fundamentals.md:166 msgid "" -"fn nice_constructor(width? : Int, height? : Int) -> Image {\n" -" ...\n" +"fn main {\n" +" let b1 : Byte = b'a'\n" +" println(b1.to_int())\n" +" let b2 = b'\\xff'\n" +" println(b2.to_int())\n" "}\n" -"\n" -"let img2 : Image = nice_constructor(width=1920, height=1080)\n" msgstr "" -#: ../../language/language.md:226 +#: ../../language/fundamentals.md:174 msgid "" -"Sometimes, it is also useful to pass a value of type `T?` directly, for " -"example when forwarding optional argument. MoonBit provides a syntax " -"`label?=value` for this, with `label?` being an abbreviation of " -"`label?=label`:" +"97\n" +"255\n" msgstr "" -#: ../../language/language.md:230 +#: ../../language/fundamentals.md:178 msgid "" -"fn image(width? : Int, height? : Int) -> Image {\n" -" ...\n" -"}\n" -"\n" -"fn fixed_width_image(height? : Int) -> Image {\n" -" image(width=1920, height?)\n" -"}\n" +"A `Bytes` is a sequence of bytes. Similar to byte, bytes literals have " +"the form of `b\"...\"`. For example:" msgstr "" -#: ../../language/language.md:236 -msgid "Autofill arguments" +#: ../../language/fundamentals.md:180 +msgid "" +"test {\n" +" let b1 : Bytes = b\"abcd\"\n" +" let b2 = b\"\\x61\\x62\\x63\\x64\"\n" +" assert_eq!(b1, b2)\n" +"}\n" msgstr "" -#: ../../language/language.md:238 -msgid "" -"MoonBit supports filling specific types of arguments automatically at " -"different call site, such as the source location of a function call. To " -"declare an autofill argument, simply declare an optional argument with " -"`_` as default value. Now if the argument is not explicitly supplied, " -"MoonBit will automatically fill it at the call site." +#: ../../language/fundamentals.md:186 +msgid "Tuple" msgstr "" -#: ../../language/language.md:242 +#: ../../language/fundamentals.md:188 msgid "" -"Currently MoonBit supports two types of autofill arguments, `SourceLoc`, " -"which is the source location of the whole function call, and `ArgsLoc`, " -"which is a array containing the source location of each argument, if any:" +"A tuple is a collection of finite values constructed using round brackets" +" `()` with the elements separated by commas `,`. The order of elements " +"matters; for example, `(1,true)` and `(true,1)` have different types. " +"Here's an example:" msgstr "" -#: ../../language/language.md:245 +#: ../../language/fundamentals.md:190 msgid "" -"fn f(_x : Int, loc~ : SourceLoc = _, args_loc~ : ArgsLoc = _) -> String {" +"fn main {\n" +" fn pack(\n" +" a : Bool,\n" +" b : Int,\n" +" c : String,\n" +" d : Double\n" +" ) -> (Bool, Int, String, Double) {\n" +" (a, b, c, d)\n" +" }\n" "\n" -" $|loc of whole function call: \\{loc}\n" -" $|loc of arguments: \\{args_loc}\n" -" // loc of whole function call: :7:3-7:10\n" -" // loc of arguments: [Some(:7:5-7:6), " -"Some(:7:8-7:9), None, None]\n" +" let quad = pack(false, 100, \"text\", 3.14)\n" +" let (bool_val, int_val, str, float_val) = quad\n" +" println(\"\\{bool_val} \\{int_val} \\{str} \\{float_val}\")\n" "}\n" msgstr "" -#: ../../language/language.md:251 -msgid "" -"Autofill arguments are very useful for writing debugging and testing " -"utilities." -msgstr "" - -#: ../../language/language.md:253 -msgid "Control Structures" -msgstr "" - -#: ../../language/language.md:255 -msgid "Conditional Expressions" +#: ../../language/fundamentals.md:198 +msgid "false 100 text 3.14\n" msgstr "" -#: ../../language/language.md:257 -msgid "" -"A conditional expression consists of a condition, a consequent, and an " -"optional else clause." +#: ../../language/fundamentals.md:202 +msgid "Tuples can be accessed via pattern matching or index:" msgstr "" -#: ../../language/language.md:259 +#: ../../language/fundamentals.md:204 msgid "" -"if x == y {\n" -" expr1\n" -"} else {\n" -" expr2\n" +"test {\n" +" let t = (1, 2)\n" +" let (x1, y1) = t\n" +" let x2 = t.0\n" +" let y2 = t.1\n" +" assert_eq!(x1, x2)\n" +" assert_eq!(y1, y2)\n" "}\n" msgstr "" -#: ../../language/language.md:266 -msgid "The else clause can also contain another if-else expression:" +#: ../../language/fundamentals.md:210 +msgid "Ref" msgstr "" -#: ../../language/language.md:268 -msgid "" -"if x == y {\n" -" expr1\n" -"}\n" +#: ../../language/fundamentals.md:212 +msgid "A `Ref[T]` is a mutable reference containing a value `val` of type `T`." msgstr "" -#: ../../language/language.md:275 +#: ../../language/fundamentals.md:214 msgid "" -"Curly brackets are used to group multiple expressions in the consequent " -"or the else clause." +"It can be constructed using `{ val : x }`, and can be accessed using " +"`ref.val`. See [struct](#struct) for detailed explanation." msgstr "" -#: ../../language/language.md:277 +#: ../../language/fundamentals.md:216 msgid "" -"Note that a conditional expression always returns a value in MoonBit, and" -" the return values of the consequent and the else clause must be of the " -"same type. Here is an example:" +"let a : Ref[Int] = { val : 100 }\n" +"\n" +"test {\n" +" a.val = 200\n" +" assert_eq!(a.val, 200)\n" +" a.val += 1\n" +" assert_eq!(a.val, 201)\n" +"}\n" msgstr "" -#: ../../language/language.md:279 -msgid "let initial = if size < 1 { 1 } else { size }\n" +#: ../../language/fundamentals.md:222 +msgid "Option and Result" msgstr "" -#: ../../language/language.md:286 -msgid "While loop" +#: ../../language/fundamentals.md:224 +msgid "" +"`Option` and `Result` are the most common types to represent a possible " +"error or failure in MoonBit." msgstr "" -#: ../../language/language.md:288 +#: ../../language/fundamentals.md:226 msgid "" -"In MoonBit, `while` loop can be used to execute a block of code " -"repeatedly as long as a condition is true. The condition is evaluated " -"before executing the block of code. The `while` loop is defined using the" -" `while` keyword, followed by a condition and the loop body. The loop " -"body is a sequence of statements. The loop body is executed as long as " -"the condition is true." +"`Option[T]` represents a possibly missing value of type `T`. It can be " +"abbreviated as `T?`." msgstr "" -#: ../../language/language.md:290 +#: ../../language/fundamentals.md:227 msgid "" -"fn main {\n" -" let mut i = 5\n" -" while i > 0 {\n" -" println(i)\n" -" i = i - 1\n" -" }\n" -"}\n" +"`Result[T, E]` represents either a value of type `T` or an error of type " +"`E`." msgstr "" -#: ../../language/language.md:298 ../../language/language.md:312 -#: ../../language/language.md:326 ../../language/language.md:340 -#: ../../language/language.md:352 ../../language/language.md:369 -#: ../../language/language.md:407 ../../language/language.md:445 -#: ../../language/language.md:459 ../../language/language.md:683 -#: ../../language/language.md:715 ../../language/language.md:742 -#: ../../language/language.md:766 ../../language/language.md:854 -#: ../../language/language.md:881 ../../language/language.md:912 -#: ../../language/language.md:939 ../../language/language.md:968 -#: ../../language/language.md:988 ../../language/language.md:1022 -#: ../../language/language.md:1036 ../../language/language.md:1159 -#: ../../language/language.md:1347 -msgid "Output" +#: ../../language/fundamentals.md:229 +msgid "See [enum](#enum) for detailed explanation." msgstr "" -#: ../../language/language.md:298 +#: ../../language/fundamentals.md:231 msgid "" -"5\n" -"4\n" -"3\n" -"2\n" -"1\n" +"test {\n" +" let a : Option[Int] = None\n" +" let b : Option[Int] = Some(42)\n" +" let c : Result[Int, String] = Ok(42)\n" +" let d : Result[Int, String] = Err(\"error\")\n" +" match a {\n" +" Some(_) => assert_true!(false)\n" +" None => assert_true!(true)\n" +" }\n" +" match d {\n" +" Ok(_) => assert_true!(false)\n" +" Err(_) => assert_true!(true)\n" +" }\n" +"}\n" msgstr "" -#: ../../language/language.md:302 -msgid "" -"The loop body supports `break` and `continue`. Using `break` allows you " -"to exit the current loop, while using `continue` skips the remaining part" -" of the current iteration and proceeds to the next iteration." +#: ../../language/fundamentals.md:237 +msgid "Array" msgstr "" -#: ../../language/language.md:304 +#: ../../language/fundamentals.md:239 msgid "" -"fn main {\n" -" let mut i = 5\n" -" while i > 0 {\n" -" i = i - 1\n" -" if i == 4 {\n" -" continue\n" -" }\n" -" if i == 1 {\n" -" break\n" -" }\n" -" println(i)\n" -" }\n" -"}\n" +"An array is a finite sequence of values constructed using square brackets" +" `[]`, with elements separated by commas `,`. For example:" msgstr "" -#: ../../language/language.md:312 -msgid "" -"3\n" -"2\n" +#: ../../language/fundamentals.md:241 +msgid "let numbers = [1, 2, 3, 4]\n" msgstr "" -#: ../../language/language.md:316 +#: ../../language/fundamentals.md:248 msgid "" -"The `while` loop also supports an optional `else` clause. When the loop " -"condition becomes false, the `else` clause will be executed, and then the" -" loop will end." +"You can use `numbers[x]` to refer to the xth element. The index starts " +"from zero." msgstr "" -#: ../../language/language.md:318 +#: ../../language/fundamentals.md:250 msgid "" -"fn main {\n" -" let mut i = 2\n" -" while i > 0 {\n" -" println(i)\n" -" i = i - 1\n" -" } else {\n" -" println(i)\n" -" }\n" +"test {\n" +" let numbers = [1, 2, 3, 4]\n" +" let a = numbers[2]\n" +" numbers[3] = 5\n" +" let b = a + numbers[3]\n" +" assert_eq!(b, 8)\n" "}\n" msgstr "" -#: ../../language/language.md:326 -msgid "" -"2\n" -"1\n" -"0\n" +#: ../../language/fundamentals.md:257 +msgid "There are `Array[T]` and `FixedArray[T]`:" msgstr "" -#: ../../language/language.md:330 -msgid "" -"When there is an `else` clause, the `while` loop can also return a value." -" The return value is the evaluation result of the `else` clause. In this " -"case, if you use `break` to exit the loop, you need to provide a return " -"value after `break`, which should be of the same type as the return value" -" of the `else` clause." +#: ../../language/fundamentals.md:259 +msgid "`Array[T]` can grow in size, while" msgstr "" -#: ../../language/language.md:332 +#: ../../language/fundamentals.md:260 msgid "" -"fn main {\n" -" let mut i = 10\n" -" let r = while i > 0 {\n" -" i = i - 1\n" -" if i % 2 == 0 {\n" -" break 5\n" -" }\n" -" } else {\n" -" 7\n" -" }\n" -" println(r)\n" -"}\n" +"`FixedArray[T]` has a fixed size, thus it needs to be created with " +"initial value." msgstr "" -#: ../../language/language.md:340 -msgid "5\n" +#: ../../language/fundamentals.md:263 +msgid "A common pitfall is creating `FixedArray` with the same initial value:" msgstr "" -#: ../../language/language.md:344 +#: ../../language/fundamentals.md:265 msgid "" -"fn main {\n" -" let mut i = 10\n" -" let r = while i > 0 {\n" -" i = i - 1\n" -" } else {\n" -" 7\n" -" }\n" -" println(r)\n" +"test {\n" +" let two_dimension_array = FixedArray::make(10, FixedArray::make(10, 0))" +"\n" +" two_dimension_array[0][5] = 10\n" +" assert_eq!(two_dimension_array[5][5], 10)\n" "}\n" msgstr "" -#: ../../language/language.md:352 -msgid "7\n" +#: ../../language/fundamentals.md:272 +msgid "" +"This is because all the cells reference to the same object (the " +"`FixedArray[Int]` in this case). One should use `FixedArray::makei()` " +"instead which creates an object for each index." msgstr "" -#: ../../language/language.md:356 -msgid "For Loop" +#: ../../language/fundamentals.md:274 +msgid "" +"test {\n" +" let two_dimension_array = FixedArray::makei(\n" +" 10, \n" +" fn (_i) { FixedArray::make(10, 0) }\n" +" )\n" +" two_dimension_array[0][5] = 10\n" +" assert_eq!(two_dimension_array[5][5], 0)\n" +"}\n" msgstr "" -#: ../../language/language.md:358 +#: ../../language/fundamentals.md:282 msgid "" -"MoonBit also supports C-style For loops. The keyword `for` is followed by" -" variable initialization clauses, loop conditions, and update clauses " -"separated by semicolons. They do not need to be enclosed in parentheses. " -"For example, the code below creates a new variable binding `i`, which has" -" a scope throughout the entire loop and is immutable. This makes it " -"easier to write clear code and reason about it:" +"When the expected type is known, MoonBit can automatically overload " +"array, otherwise `Array[T]` is created:" msgstr "" -#: ../../language/language.md:361 +#: ../../language/fundamentals.md:285 msgid "" -"fn main {\n" -" for i = 0; i < 5; i = i + 1 {\n" -" println(i)\n" -" }\n" -"}\n" +"let fixed_array_1 : FixedArray[Int] = [1, 2, 3]\n" +"let fixed_array_2 = ([1, 2, 3] : FixedArray[Int])\n" +"let array_3 = [1, 2, 3] // Array[Int]\n" msgstr "" -#: ../../language/language.md:369 -msgid "" -"0\n" -"1\n" -"2\n" -"3\n" -"4\n" +#: ../../language/fundamentals.md:291 +msgid "ArrayView" msgstr "" -#: ../../language/language.md:373 -msgid "The variable initialization clause can create multiple bindings:" +#: ../../language/fundamentals.md:293 +msgid "" +"Analogous to `slice` in other languages, the view is a reference to a " +"specific segment of collections. You can use `data[start:end]` to create " +"a view of array `data`, referencing elements from `start` to `end` " +"(exclusive). Both `start` and `end` indices can be omitted." msgstr "" -#: ../../language/language.md:375 +#: ../../language/fundamentals.md:298 msgid "" -"for i = 0, j = 0; i + j < 100; i = i + 1, j = j + 1 {\n" -" println(i)\n" +"test {\n" +" let xs = [0, 1, 2, 3, 4, 5]\n" +" let s1 : ArrayView[Int] = xs[2:]\n" +" inspect!(s1, content=\"[2, 3, 4, 5]\")\n" +" inspect!(xs[:4], content=\"[0, 1, 2, 3]\")\n" +" inspect!(xs[2:5], content=\"[2, 3, 4]\")\n" +" inspect!(xs[:], content=\"[0, 1, 2, 3, 4, 5]\")\n" "}\n" msgstr "" -#: ../../language/language.md:382 -msgid "" -"It should be noted that in the update clause, when there are multiple " -"binding variables, the semantics are to update them simultaneously. In " -"other words, in the example above, the update clause does not execute `i " -"= i + 1`, `j = j + 1` sequentially, but rather increments `i` and `j` at " -"the same time. Therefore, when reading the values of the binding " -"variables in the update clause, you will always get the values updated in" -" the previous iteration." +#: ../../language/fundamentals.md:304 +msgid "Map" msgstr "" -#: ../../language/language.md:384 +#: ../../language/fundamentals.md:306 msgid "" -"Variable initialization clauses, loop conditions, and update clauses are " -"all optional. For example, the following two are infinite loops:" +"MoonBit provides a hash map data structure that preserves insertion order" +" called `Map` in its standard library. `Map`s can be created via a " +"convenient literal syntax:" msgstr "" -#: ../../language/language.md:386 -msgid "" -"for i = 1; ; i = i + 1 {\n" -" println(i)\n" -"}\n" -"for {\n" -" println(\"loop forever\")\n" -"}\n" +#: ../../language/fundamentals.md:309 +msgid "let map : Map[String, Int] = { \"x\": 1, \"y\": 2, \"z\": 3 }\n" msgstr "" -#: ../../language/language.md:393 +#: ../../language/fundamentals.md:315 msgid "" -"The `for` loop also supports `continue`, `break`, and `else` clauses. " -"Like the `while` loop, the `for` loop can also return a value using the " -"`break` and `else` clauses." +"Currently keys in map literal syntax must be constant. `Map`s can also be" +" destructed elegantly with pattern matching, see [Map Pattern](#map-" +"pattern)." msgstr "" -#: ../../language/language.md:395 -msgid "" -"The `continue` statement skips the remaining part of the current " -"iteration of the `for` loop (including the update clause) and proceeds to" -" the next iteration. The `continue` statement can also update the binding" -" variables of the `for` loop, as long as it is followed by expressions " -"that match the number of binding variables, separated by commas." +#: ../../language/fundamentals.md:317 +msgid "Json literal" msgstr "" -#: ../../language/language.md:397 +#: ../../language/fundamentals.md:319 msgid "" -"For example, the following program calculates the sum of even numbers " -"from 1 to 6:" +"MoonBit supports convenient json handling by overloading literals. When " +"the expected type of an expression is `Json`, number, string, array and " +"map literals can be directly used to create json data:" msgstr "" -#: ../../language/language.md:399 +#: ../../language/fundamentals.md:322 msgid "" -"fn main {\n" -" let sum = for i = 1, acc = 0; i <= 6; i = i + 1 {\n" -" if i % 2 == 0 {\n" -" println(\"even: \\{i}\")\n" -" continue i + 1, acc + i\n" -" }\n" -" } else {\n" -" acc\n" -" }\n" -" println(sum)\n" +"let moon_pkg_json_example : Json = {\n" +" \"import\": [\"moonbitlang/core/builtin\", " +"\"moonbitlang/core/coverage\"],\n" +" \"test-import\": [\"moonbitlang/core/random\"],\n" "}\n" msgstr "" -#: ../../language/language.md:407 -msgid "" -"even: 2\n" -"even: 4\n" -"even: 6\n" -"12\n" +#: ../../language/fundamentals.md:328 +msgid "Json values can be pattern matched too, see [Json Pattern](#json-pattern)." msgstr "" -#: ../../language/language.md:411 -msgid "`for .. in` loop" +#: ../../language/fundamentals.md:330 +msgid "Functions" msgstr "" -#: ../../language/language.md:413 +#: ../../language/fundamentals.md:332 msgid "" -"MoonBit supports traversing elements of different data structures and " -"sequences via the `for .. in` loop syntax:" +"Functions take arguments and produce a result. In MoonBit, functions are " +"first-class, which means that functions can be arguments or return values" +" of other functions. MoonBit's naming convention requires that function " +"names should not begin with uppercase letters (A-Z). Compare for " +"constructors in the `enum` section below." msgstr "" -#: ../../language/language.md:415 -msgid "" -"for x in [1, 2, 3] {\n" -" println(x)\n" -"}\n" +#: ../../language/fundamentals.md:334 +msgid "Top-Level Functions" msgstr "" -#: ../../language/language.md:422 +#: ../../language/fundamentals.md:336 msgid "" -"`for .. in` loop is translated to the use of `Iter` in MoonBit's standard" -" library. Any type with a method `.iter() : Iter[T]` can be traversed " -"using `for .. in`. For more information of the `Iter` type, see " -"[Iterator](#iterator) below." +"Functions can be defined as top-level or local. We can use the `fn` " +"keyword to define a top-level function that sums three integers and " +"returns the result, as follows:" msgstr "" -#: ../../language/language.md:425 +#: ../../language/fundamentals.md:338 msgid "" -"In addition to sequences of a single value, MoonBit also supports " -"traversing sequences of two values, such as `Map`, via the `Iter2` type " -"in MoonBit's standard library. Any type with method `.iter2() : Iter2[A, " -"B]` can be traversed using `for .. in` with two loop variables:" +"fn add3(x : Int, y : Int, z : Int) -> Int {\n" +" x + y + z\n" +"}\n" msgstr "" -#: ../../language/language.md:428 +#: ../../language/fundamentals.md:344 msgid "" -"for k, v in { \"x\": 1, \"y\": 2, \"z\": 3 } {\n" -" println(k)\n" -" println(v)\n" -"}\n" +"Note that the arguments and return value of top-level functions require " +"**explicit** type annotations." +msgstr "" + +#: ../../language/fundamentals.md:346 +msgid "Local Functions" msgstr "" -#: ../../language/language.md:435 +#: ../../language/fundamentals.md:348 msgid "" -"Another example of `for .. in` with two loop variables is traversing an " -"array while keeping track of array index:" +"Local functions can be named or anonymous. Type annotations can be " +"omitted for local function definitions: they can be automatically " +"inferred in most cases. For example:" msgstr "" -#: ../../language/language.md:437 +#: ../../language/fundamentals.md:350 msgid "" -"fn main {\n" -" for index, elem in [4, 5, 6] {\n" -" let i = index + 1\n" -" println(\"The \\{i}-th element of the array is \\{elem}\")\n" +"fn local_1() -> Int {\n" +" fn inc(x) { // named as `inc`\n" +" x + 1\n" " }\n" +" // anonymous, instantly applied to integer literal 6\n" +" (fn(x) { x + inc(2) })(6)\n" +"}\n" +"\n" +"test {\n" +" assert_eq!(local_1(), 9)\n" "}\n" msgstr "" -#: ../../language/language.md:445 +#: ../../language/fundamentals.md:356 msgid "" -"The 1-th element of the array is 4\n" -"The 2-th element of the array is 5\n" -"The 3-th element of the array is 6\n" +"There's also a form called **matrix function** that make use of [pattern " +"matching](#pattern-matching):" msgstr "" -#: ../../language/language.md:449 +#: ../../language/fundamentals.md:358 msgid "" -"Control flow operations such as `return`, `break` and error handling are " -"supported in the body of `for .. in` loop:" +"let extract : (Int?, Int) -> Int = fn {\n" +" Some(x), _ => x\n" +" None, default => default\n" +"}\n" msgstr "" -#: ../../language/language.md:451 +#: ../../language/fundamentals.md:364 msgid "" -"fn main {\n" -" let map = { \"x\": 1, \"y\": 2, \"z\": 3, \"w\": 4 }\n" -" for k, v in map {\n" -" if k == \"y\" {\n" -" continue\n" -" }\n" -" println(\"\\{k}, \\{v}\")\n" -" if k == \"z\" {\n" -" break\n" -" }\n" -" }\n" -"}\n" +"Functions, whether named or anonymous, are _lexical closures_: any " +"identifiers without a local binding must refer to bindings from a " +"surrounding lexical scope. For example:" msgstr "" -#: ../../language/language.md:459 +#: ../../language/fundamentals.md:366 msgid "" -"x, 1\n" -"z, 3\n" +"let global_y = 3\n" +"\n" +"fn local_2(x : Int) -> (Int, Int) {\n" +" fn inc() {\n" +" x + 1\n" +" }\n" +"\n" +" fn four() {\n" +" global_y + 1\n" +" }\n" +"\n" +" (inc(), four())\n" +"}\n" +"\n" +"test {\n" +" assert_eq!(local_2(3), (4, 4))\n" +"}\n" msgstr "" -#: ../../language/language.md:463 -msgid "If a loop variable is unused, it can be ignored with `_`." +#: ../../language/fundamentals.md:372 +msgid "Function Applications" msgstr "" -#: ../../language/language.md:465 -msgid "Functional loop" +#: ../../language/fundamentals.md:374 +msgid "A function can be applied to a list of arguments in parentheses:" msgstr "" -#: ../../language/language.md:467 -msgid "" -"Functional loop is a powerful feature in MoonBit that enables you to " -"write loops in a functional style." +#: ../../language/fundamentals.md:376 +msgid "add3(1, 2, 7)\n" msgstr "" -#: ../../language/language.md:469 +#: ../../language/fundamentals.md:380 msgid "" -"A functional loop consumes arguments and returns a value. It is defined " -"using the `loop` keyword, followed by its arguments and the loop body. " -"The loop body is a sequence of clauses, each of which consists of a " -"pattern and an expression. The clause whose pattern matches the input " -"will be executed, and the loop will return the value of the expression. " -"If no pattern matches, the loop will panic. Use the `continue` keyword " -"with arguments to start the next iteration of the loop. Use the `break` " -"keyword with arguments to return a value from the loop. The `break` " -"keyword can be omitted if the value is the last expression in the loop " -"body." +"This works whether `add3` is a function defined with a name (as in the " +"previous example), or a variable bound to a function value, as shown " +"below:" msgstr "" -#: ../../language/language.md:471 +#: ../../language/fundamentals.md:382 msgid "" "test {\n" -" fn sum(xs : @immut/list.T[Int]) -> Int {\n" -" loop xs, 0 {\n" -" Nil, acc => break acc // <=> Nil, acc => acc\n" -" Cons(x, rest), acc => continue rest, x + acc\n" -" }\n" -" }\n" -"\n" -" assert_eq!(sum(Cons(1, Cons(2, Cons(3, Nil)))), 6)\n" +" let add3 = fn(x, y, z) { x + y + z }\n" +" assert_eq!(add3(1, 2, 7), 10)\n" "}\n" msgstr "" -#: ../../language/language.md:477 -msgid "Guard Statement" +#: ../../language/fundamentals.md:388 +msgid "" +"The expression `add3(1, 2, 7)` returns `10`. Any expression that " +"evaluates to a function value is applicable:" msgstr "" -#: ../../language/language.md:479 +#: ../../language/fundamentals.md:390 msgid "" -"The `guard` statement is used to check a specified invariant. If the " -"condition of the invariant is satisfied, the program continues executing " -"the subsequent statements and returns. If the condition is not satisfied " -"(i.e., false), the code in the `else` block is executed and its " -"evaluation result is returned (the subsequent statements are skipped)." +"test {\n" +" let f = fn(x) { x + 1 }\n" +" let g = fn(x) { x + 2 }\n" +" let w = (if true { f } else { g })(3)\n" +" assert_eq!(w, 4)\n" +"}\n" msgstr "" -#: ../../language/language.md:484 -msgid "guard index >= 0 && index < len else { abort(\"Index out of range\") }\n" +#: ../../language/fundamentals.md:397 +msgid "Labelled arguments" msgstr "" -#: ../../language/language.md:491 +#: ../../language/fundamentals.md:399 msgid "" -"The `guard` statement also supports pattern matching: in the following " -"example, `getProcessedText` assumes that the input `path` points to " -"resources that are all plain text, and it uses the `guard` statement to " -"ensure this invariant. Compared to using a `match` statement, the " -"subsequent processing of `text` can have one less level of indentation." +"**Top-level** functions can declare labelled argument with the syntax " +"`label~ : Type`. `label` will also serve as parameter name inside " +"function body:" msgstr "" -#: ../../language/language.md:496 +#: ../../language/fundamentals.md:401 msgid "" -"enum Resource {\n" -" Folder(Array[String])\n" -" PlainText(String)\n" -" JsonConfig(Json)\n" -"}\n" -"\n" -"fn getProcessedText(\n" -" resources : Map[String, Resource],\n" -" path : String\n" -") -> String!Error {\n" -" guard let Some(PlainText(text)) = resources[path] else {\n" -" None => fail!(\"\\{path} not found\")\n" -" Some(Folder(_)) => fail!(\"\\{path} is a folder\")\n" -" Some(JsonConfig(_)) => fail!(\"\\{path} is a json config\")\n" -" }\n" -" process(text)\n" +"fn labelled_1(arg1~ : Int, arg2~ : Int) -> Int {\n" +" arg1 + arg2\n" "}\n" msgstr "" -#: ../../language/language.md:502 +#: ../../language/fundamentals.md:407 msgid "" -"When the `else` part is omitted, the program terminates if the condition " -"specified in the `guard` statement is not true or cannot be matched." +"Labelled arguments can be supplied via the syntax `label=arg`. " +"`label=label` can be abbreviated as `label~`:" msgstr "" -#: ../../language/language.md:505 +#: ../../language/fundamentals.md:409 msgid "" -"guard condition // <=> guard condition else { panic() }\n" -"guard let Some(x) = expr\n" -"// <=> guard let Some(x) = expr else { _ => panic() }\n" +"test {\n" +" let arg1 = 1\n" +" assert_eq!(labelled_1(arg2=2, arg1~), 3)\n" +"}\n" msgstr "" -#: ../../language/language.md:512 -msgid "Iterator" +#: ../../language/fundamentals.md:415 +msgid "" +"Labelled function can be supplied in any order. The evaluation order of " +"arguments is the same as the order of parameters in function declaration." msgstr "" -#: ../../language/language.md:514 -msgid "" -"An iterator is an object that traverse through a sequence while providing" -" access to its elements. Traditional OO languages like Java's " -"`Iterator` use `next()` `hasNext()` to step through the iteration " -"process, whereas functional languages (JavaScript's `forEach`, Lisp's " -"`mapcar`) provides a high-order function which takes an operation and a " -"sequence then consumes the sequence with that operation being applied to " -"the sequence. The former is called _external iterator_ (visible to user) " -"and the latter is called _internal iterator_ (invisible to user)." +#: ../../language/fundamentals.md:417 +msgid "Optional arguments" msgstr "" -#: ../../language/language.md:522 +#: ../../language/fundamentals.md:419 msgid "" -"The built-in type `Iter[T]` is MoonBit's internal iterator " -"implementation. Almost all built-in sequential data structures have " -"implemented `Iter`:" +"A labelled argument can be made optional by supplying a default " +"expression with the syntax `label~ : Type = default_expr`. If this " +"argument is not supplied at call site, the default expression will be " +"used:" msgstr "" -#: ../../language/language.md:525 +#: ../../language/fundamentals.md:421 msgid "" -"fn filter_even(l : Array[Int]) -> Array[Int] {\n" -" let l_iter : Iter[Int] = l.iter()\n" -" l_iter.filter(fn { x => (x & 1) == 0 }).collect()\n" +"fn optional(opt~ : Int = 42) -> Int {\n" +" opt\n" "}\n" "\n" -"fn fact(n : Int) -> Int {\n" -" let start = 1\n" -" let range : Iter[Int] = start.until(n)\n" -" range.fold(Int::op_mul, init=start)\n" +"test {\n" +" assert_eq!(optional(), 42)\n" +" assert_eq!(optional(opt=0), 0)\n" "}\n" msgstr "" -#: ../../language/language.md:531 -msgid "Commonly used methods include:" -msgstr "" - -#: ../../language/language.md:533 +#: ../../language/fundamentals.md:427 msgid "" -"`each`: Iterates over each element in the iterator, applying some " -"function to each element." +"The default expression will be evaluated every time it is used. And the " +"side effect in the default expression, if any, will also be triggered. " +"For example:" msgstr "" -#: ../../language/language.md:534 +#: ../../language/fundamentals.md:429 msgid "" -"`fold`: Folds the elements of the iterator using the given function, " -"starting with the given initial value." -msgstr "" - -#: ../../language/language.md:535 -msgid "`collect`: Collects the elements of the iterator into an array." +"fn incr(counter~ : Ref[Int] = { val: 0 }) -> Ref[Int] {\n" +" counter.val = counter.val + 1\n" +" counter\n" +"}\n" +"\n" +"test {\n" +" inspect!(incr(), content=\"{val: 1}\")\n" +" inspect!(incr(), content=\"{val: 1}\")\n" +" let counter : Ref[Int] = { val: 0 }\n" +" inspect!(incr(counter~), content=\"{val: 1}\")\n" +" inspect!(incr(counter~), content=\"{val: 2}\")\n" +"}\n" msgstr "" -#: ../../language/language.md:537 +#: ../../language/fundamentals.md:435 msgid "" -"`filter`: _lazy_ Filters the elements of the iterator based on a " -"predicate function." +"If you want to share the result of default expression between different " +"function calls, you can lift the default expression to a toplevel `let` " +"declaration:" msgstr "" -#: ../../language/language.md:538 +#: ../../language/fundamentals.md:437 msgid "" -"`map`: _lazy_ Transforms the elements of the iterator using a mapping " -"function." +"let default_counter : Ref[Int] = { val: 0 }\n" +"\n" +"fn incr_2(counter~ : Ref[Int] = default_counter) -> Int {\n" +" counter.val = counter.val + 1\n" +" counter.val\n" +"}\n" +"\n" +"test {\n" +" assert_eq!(incr_2(), 1)\n" +" assert_eq!(incr_2(), 2)\n" +"}\n" msgstr "" -#: ../../language/language.md:539 +#: ../../language/fundamentals.md:443 msgid "" -"`concat`: _lazy_ Combines two iterators into one by appending the " -"elements of the second iterator to the first." +"Default expression can depend on the value of previous arguments. For " +"example:" msgstr "" -#: ../../language/language.md:541 +#: ../../language/fundamentals.md:445 msgid "" -"Methods like `filter` `map` are very common on a sequence object e.g. " -"Array. But what makes `Iter` special is that any method that constructs a" -" new `Iter` is _lazy_ (i.e. iteration doesn't start on call because it's " -"wrapped inside a function), as a result of no allocation for intermediate" -" value. That's what makes `Iter` superior for traversing through " -"sequence: no extra cost. MoonBit encourages user to pass an `Iter` across" -" functions instead of the sequence object itself." +"fn sub_array[X](\n" +" xs : Array[X],\n" +" offset~ : Int,\n" +" len~ : Int = xs.length() - offset\n" +") -> Array[X] {\n" +" xs[offset:offset + len].iter().to_array()\n" +"}\n" +"\n" +"test {\n" +" assert_eq!(sub_array([1, 2, 3], offset=1), [2, 3])\n" +" assert_eq!(sub_array([1, 2, 3], offset=1, len=1), [2])\n" +"}\n" msgstr "" -#: ../../language/language.md:549 -msgid "" -"Pre-defined sequence structures like `Array` and its iterators should be " -"enough to use. But to take advantages of these methods when used with a " -"custom sequence with elements of type `S`, we will need to implement " -"`Iter`, namely, a function that returns an `Iter[S]`. Take `Bytes` as an " -"example:" +#: ../../language/fundamentals.md:452 +msgid "Automatically insert `Some` when supplying optional arguments" msgstr "" -#: ../../language/language.md:554 +#: ../../language/fundamentals.md:454 msgid "" -"fn iter(data : Bytes) -> Iter[Byte] {\n" -" Iter::new(\n" -" fn(visit : (Byte) -> IterResult) -> IterResult {\n" -" for byte in data {\n" -" if visit(byte) == IterEnd {\n" -" break IterEnd\n" -" }\n" -" } else {\n" -" IterContinue\n" -" }\n" -" },\n" -" )\n" -"}\n" +"It is quite often optional arguments have type `T?` with `None` as " +"default value. In this case, passing the argument explicitly requires " +"wrapping a `Some`, which is ugly:" msgstr "" -#: ../../language/language.md:560 +#: ../../language/fundamentals.md:458 msgid "" -"Almost all `Iter` implementations are identical to that of `Bytes`, the " -"only main difference being the code block that actually does the " -"iteration." +"fn ugly_constructor(width~ : Int? = None, height~ : Int? = None) -> Image" +" {\n" +" ...\n" +"}\n" +"\n" +"let img : Image = ugly_constructor(width=Some(1920), height=Some(1080))\n" msgstr "" -#: ../../language/language.md:563 -msgid "Implementation details" +#: ../../language/fundamentals.md:464 +msgid "" +"Fortunately, MoonBit provides a special kind of optional arguments to " +"solve this problem. Optional arguments declared with `label? : T` has " +"type `T?` and `None` as default value. When supplying this kind of " +"optional argument directly, MoonBit will automatically insert a `Some`:" msgstr "" -#: ../../language/language.md:565 +#: ../../language/fundamentals.md:468 msgid "" -"The type `Iter[T]` is basically a type alias for `((T) -> IterResult) -> " -"IterResult`, a higher-order function that takes an operation and " -"`IterResult` is an enum object that tracks the state of current iteration" -" which consists any of the 2 states:" +"fn nice_constructor(width? : Int, height? : Int) -> Image {\n" +" ...\n" +"}\n" +"\n" +"let img2 : Image = nice_constructor(width=1920, height=1080)\n" msgstr "" -#: ../../language/language.md:570 -msgid "`IterEnd`: marking the end of an iteration" +#: ../../language/fundamentals.md:474 +msgid "" +"Sometimes, it is also useful to pass a value of type `T?` directly, for " +"example when forwarding optional argument. MoonBit provides a syntax " +"`label?=value` for this, with `label?` being an abbreviation of " +"`label?=label`:" msgstr "" -#: ../../language/language.md:571 +#: ../../language/fundamentals.md:478 msgid "" -"`IterContinue`: marking the end of an iteration is yet to be reached, " -"implying the iteration will still continue at this state." +"fn image(width? : Int, height? : Int) -> Image {\n" +" ...\n" +"}\n" +"\n" +"fn fixed_width_image(height? : Int) -> Image {\n" +" image(width=1920, height?)\n" +"}\n" +msgstr "" + +#: ../../language/fundamentals.md:484 +msgid "Autofill arguments" msgstr "" -#: ../../language/language.md:573 +#: ../../language/fundamentals.md:486 msgid "" -"To put it simply, `Iter[T]` takes a function `(T) -> IterResult` and use " -"it to transform `Iter[T]` itself to a new state of type `IterResult`. " -"Whether that state being `IterEnd` `IterContinue` depends on the " -"function." +"MoonBit supports filling specific types of arguments automatically at " +"different call site, such as the source location of a function call. To " +"declare an autofill argument, simply declare an optional argument with " +"`_` as default value. Now if the argument is not explicitly supplied, " +"MoonBit will automatically fill it at the call site." msgstr "" -#: ../../language/language.md:577 +#: ../../language/fundamentals.md:490 msgid "" -"Iterator provides a unified way to iterate through data structures, and " -"they can be constructed at basically no cost: as long as `fn(yield)` " -"doesn't execute, the iteration process doesn't start." +"Currently MoonBit supports two types of autofill arguments, `SourceLoc`, " +"which is the source location of the whole function call, and `ArgsLoc`, " +"which is a array containing the source location of each argument, if any:" msgstr "" -#: ../../language/language.md:581 +#: ../../language/fundamentals.md:493 msgid "" -"Internally a `Iter::run()` is used to trigger the iteration. Chaining all" -" sorts of `Iter` methods might be visually pleasing, but do notice the " -"heavy work underneath the abstraction." +"fn f(_x : Int, loc~ : SourceLoc = _, args_loc~ : ArgsLoc = _) -> String {" +"\n" +" $|loc of whole function call: \\{loc}\n" +" $|loc of arguments: \\{args_loc}\n" +" // loc of whole function call: :7:3-7:10\n" +" // loc of arguments: [Some(:7:5-7:6), " +"Some(:7:8-7:9), None, None]\n" +"}\n" msgstr "" -#: ../../language/language.md:585 +#: ../../language/fundamentals.md:499 msgid "" -"Thus, unlike an external iterator, once the iteration starts there's no " -"way to stop unless the end is reached. Methods such as `count()` which " -"counts the number of elements in a iterator looks like an `O(1)` " -"operation but actually has linear time complexity. Carefully use " -"iterators or performance issue might occur." +"Autofill arguments are very useful for writing debugging and testing " +"utilities." msgstr "" -#: ../../language/language.md:591 -msgid "Built-in Data Structures" +#: ../../language/fundamentals.md:501 +msgid "Control Structures" msgstr "" -#: ../../language/language.md:593 -msgid "Boolean" +#: ../../language/fundamentals.md:503 +msgid "Conditional Expressions" msgstr "" -#: ../../language/language.md:595 +#: ../../language/fundamentals.md:505 msgid "" -"MoonBit has a built-in boolean type, which has two values: `true` and " -"`false`. The boolean type is used in conditional expressions and control " -"structures." +"A conditional expression consists of a condition, a consequent, and an " +"optional `else` clause or `else if` clause." msgstr "" -#: ../../language/language.md:597 +#: ../../language/fundamentals.md:507 msgid "" -"let a = true\n" -"let b = false\n" -"let c = a && b\n" -"let d = a || b\n" -"let e = not(a)\n" +"if x == y {\n" +" expr1\n" +"} else if x == z {\n" +" expr2\n" +"} else {\n" +" expr3\n" +"}\n" msgstr "" -#: ../../language/language.md:604 -msgid "Number" +#: ../../language/fundamentals.md:514 +msgid "The curly brackets around the consequent are required." msgstr "" -#: ../../language/language.md:606 -msgid "MoonBit have integer type and floating point type:" +#: ../../language/fundamentals.md:516 +msgid "" +"Note that a conditional expression always returns a value in MoonBit, and" +" the return values of the consequent and the else clause must be of the " +"same type. Here is an example:" msgstr "" -#: ../../language/language.md:597 -msgid "type" +#: ../../language/fundamentals.md:518 +msgid "let initial = if size < 1 { 1 } else { size }\n" msgstr "" -#: ../../language/language.md:597 ../../language/language.md:683 -msgid "description" +#: ../../language/fundamentals.md:525 +msgid "The `else` clause can only be omitted if the return value has type `Unit`." msgstr "" -#: ../../language/language.md:597 -msgid "example" +#: ../../language/fundamentals.md:527 +msgid "Match Expression" msgstr "" -#: ../../language/language.md:597 -msgid "`Int`" +#: ../../language/fundamentals.md:529 +msgid "" +"The `match` expression is similar to conditional expression, but it uses " +"[pattern matching](#pattern-matching) to decide which consequent to " +"evaluate and extracting variables at the same time." msgstr "" -#: ../../language/language.md:597 -msgid "32-bit signed integer" +#: ../../language/fundamentals.md:531 +msgid "" +"fn decide_sport(weather : String, humidity : Int) -> String {\n" +" match weather {\n" +" \"sunny\" => \"tennis\"\n" +" \"rainy\" => if humidity > 80 { \"swimming\" } else { \"football\" }\n" +" _ => \"unknown\"\n" +" }\n" +"}\n" +"\n" +"test {\n" +" assert_eq!(decide_sport(\"sunny\", 0), \"tennis\")\n" +"}\n" msgstr "" -#: ../../language/language.md:597 -msgid "`42`" +#: ../../language/fundamentals.md:538 +msgid "" +"If a possible condition is omitted, the compiler will issue a warning, " +"and the program will terminate if that case were reached." msgstr "" -#: ../../language/language.md:597 -msgid "`Int64`" +#: ../../language/fundamentals.md:540 +msgid "Guard Statement" msgstr "" -#: ../../language/language.md:597 -msgid "64-bit signed integer" +#: ../../language/fundamentals.md:542 +msgid "" +"The `guard` statement is used to check a specified invariant. If the " +"condition of the invariant is satisfied, the program continues executing " +"the subsequent statements and returns. If the condition is not satisfied " +"(i.e., false), the code in the `else` block is executed and its " +"evaluation result is returned (the subsequent statements are skipped)." msgstr "" -#: ../../language/language.md:597 -msgid "`1000L`" +#: ../../language/fundamentals.md:547 +msgid "" +"fn guarded_get(array : Array[Int], index : Int) -> Int? {\n" +" guard index >= 0 && index < array.length() else { None }\n" +" Some(array[index])\n" +"}\n" +"\n" +"test {\n" +" inspect!(guarded_get([1, 2, 3], -1), content=\"None\")\n" +"}\n" msgstr "" -#: ../../language/language.md:597 -msgid "`UInt`" +#: ../../language/fundamentals.md:554 +msgid "Guarded Let" msgstr "" -#: ../../language/language.md:597 -msgid "32-bit unsigned integer" +#: ../../language/fundamentals.md:556 +msgid "" +"The `let` statement can be used with [pattern matching](#pattern-" +"matching). However, `let` statement can only handle one case. And `guard " +"let` can solve this issue." msgstr "" -#: ../../language/language.md:597 -msgid "`14U`" +#: ../../language/fundamentals.md:558 +msgid "" +"In the following example, `getProcessedText` assumes that the input " +"`path` points to resources that are all plain text, and it uses the " +"`guard` statement to ensure this invariant. Compared to using a `match` " +"statement, the subsequent processing of `text` can have one less level of" +" indentation." msgstr "" -#: ../../language/language.md:597 -msgid "`UInt64`" +#: ../../language/fundamentals.md:562 +msgid "" +"enum Resource {\n" +" Folder(Array[String])\n" +" PlainText(String)\n" +" JsonConfig(Json)\n" +"}\n" +"\n" +"fn getProcessedText(\n" +" resources : Map[String, Resource],\n" +" path : String\n" +") -> String!Error {\n" +" guard let Some(PlainText(text)) = resources[path] else {\n" +" None => fail!(\"\\{path} not found\")\n" +" Some(Folder(_)) => fail!(\"\\{path} is a folder\")\n" +" Some(JsonConfig(_)) => fail!(\"\\{path} is a json config\")\n" +" }\n" +" process(text)\n" +"}\n" msgstr "" -#: ../../language/language.md:597 -msgid "64-bit unsigned integer" +#: ../../language/fundamentals.md:568 +msgid "" +"When the `else` part is omitted, the program terminates if the condition " +"specified in the `guard` statement is not true or cannot be matched." msgstr "" -#: ../../language/language.md:597 -msgid "`14UL`" +#: ../../language/fundamentals.md:571 +msgid "" +"guard condition // <=> guard condition else { panic() }\n" +"guard let Some(x) = expr\n" +"// <=> guard let Some(x) = expr else { _ => panic() }\n" msgstr "" -#: ../../language/language.md:597 -msgid "`Double`" +#: ../../language/fundamentals.md:578 +msgid "While loop" msgstr "" -#: ../../language/language.md:597 -msgid "64-bit floating point, defined by IEEE754" +#: ../../language/fundamentals.md:580 +msgid "" +"In MoonBit, `while` loop can be used to execute a block of code " +"repeatedly as long as a condition is true. The condition is evaluated " +"before executing the block of code. The `while` loop is defined using the" +" `while` keyword, followed by a condition and the loop body. The loop " +"body is a sequence of statements. The loop body is executed as long as " +"the condition is true." msgstr "" -#: ../../language/language.md:597 -msgid "`3.14`" +#: ../../language/fundamentals.md:582 +msgid "" +"fn main {\n" +" let mut i = 5\n" +" while i > 0 {\n" +" println(i)\n" +" i = i - 1\n" +" }\n" +"}\n" msgstr "" -#: ../../language/language.md:597 -msgid "`Float`" +#: ../../language/fundamentals.md:590 +msgid "" +"5\n" +"4\n" +"3\n" +"2\n" +"1\n" msgstr "" -#: ../../language/language.md:597 -msgid "32-bit floating point" +#: ../../language/fundamentals.md:594 +msgid "" +"The loop body supports `break` and `continue`. Using `break` allows you " +"to exit the current loop, while using `continue` skips the remaining part" +" of the current iteration and proceeds to the next iteration." msgstr "" -#: ../../language/language.md:597 -msgid "`(3.14 : Float)`" +#: ../../language/fundamentals.md:596 +msgid "" +"fn main {\n" +" let mut i = 5\n" +" while i > 0 {\n" +" i = i - 1\n" +" if i == 4 {\n" +" continue\n" +" }\n" +" if i == 1 {\n" +" break\n" +" }\n" +" println(i)\n" +" }\n" +"}\n" msgstr "" -#: ../../language/language.md:597 -msgid "`BigInt`" +#: ../../language/fundamentals.md:604 +msgid "" +"3\n" +"2\n" msgstr "" -#: ../../language/language.md:597 -msgid "represents numeric values larger than other types" +#: ../../language/fundamentals.md:608 +msgid "" +"The `while` loop also supports an optional `else` clause. When the loop " +"condition becomes false, the `else` clause will be executed, and then the" +" loop will end." msgstr "" -#: ../../language/language.md:597 -msgid "`10000000000000000000000N`" +#: ../../language/fundamentals.md:610 +msgid "" +"fn main {\n" +" let mut i = 2\n" +" while i > 0 {\n" +" println(i)\n" +" i = i - 1\n" +" } else {\n" +" println(i)\n" +" }\n" +"}\n" msgstr "" -#: ../../language/language.md:618 +#: ../../language/fundamentals.md:618 msgid "" -"MoonBit also supports numeric literals, including decimal, binary, octal," -" and hexadecimal numbers." +"2\n" +"1\n" +"0\n" msgstr "" -#: ../../language/language.md:620 +#: ../../language/fundamentals.md:622 msgid "" -"To improve readability, you may place underscores in the middle of " -"numeric literals such as `1_000_000`. Note that underscores can be placed" -" anywhere within a number, not just every three digits." +"When there is an `else` clause, the `while` loop can also return a value." +" The return value is the evaluation result of the `else` clause. In this " +"case, if you use `break` to exit the loop, you need to provide a return " +"value after `break`, which should be of the same type as the return value" +" of the `else` clause." msgstr "" -#: ../../language/language.md:622 -msgid "There is nothing surprising about decimal numbers." +#: ../../language/fundamentals.md:624 +msgid "" +"fn main {\n" +" let mut i = 10\n" +" let r = while i > 0 {\n" +" i = i - 1\n" +" if i % 2 == 0 {\n" +" break 5\n" +" }\n" +" } else {\n" +" 7\n" +" }\n" +" println(r)\n" +"}\n" msgstr "" -#: ../../language/language.md:624 -msgid "" -"let a = 1234\n" -"let b = 1_000_000 + a\n" -"// UInt : 0_U\n" -"let unsigned_num = 4_294_967_295U\n" -"// Int64 : 0_L\n" -"let large_num = 9_223_372_036_854_775_807L\n" -"// UInt64 : 0_UL\n" -"let unsigned_large_num = 18_446_744_073_709_551_615UL\n" +#: ../../language/fundamentals.md:632 +msgid "5\n" msgstr "" -#: ../../language/language.md:631 +#: ../../language/fundamentals.md:636 msgid "" -"A binary number has a leading zero followed by a letter \"B\", i.e. " -"`0b`/`0B`. Note that the digits after `0b`/`0B` must be `0` or `1`." +"fn main {\n" +" let mut i = 10\n" +" let r = while i > 0 {\n" +" i = i - 1\n" +" } else {\n" +" 7\n" +" }\n" +" println(r)\n" +"}\n" msgstr "" -#: ../../language/language.md:634 -msgid "" -"let bin = 0b110010\n" -"let another_bin = 0B110010\n" +#: ../../language/fundamentals.md:644 +msgid "7\n" msgstr "" -#: ../../language/language.md:641 -msgid "" -"An octal number has a leading zero followed by a letter \"O\", i.e. " -"`0o`/`0O`. Note that the digits after `0o`/`0O` must be in the range from" -" `0` through `7`:" +#: ../../language/fundamentals.md:648 +msgid "For Loop" msgstr "" -#: ../../language/language.md:644 +#: ../../language/fundamentals.md:650 msgid "" -"let octal = 0o1234\n" -"let another_octal = 0O1234\n" +"MoonBit also supports C-style For loops. The keyword `for` is followed by" +" variable initialization clauses, loop conditions, and update clauses " +"separated by semicolons. They do not need to be enclosed in parentheses. " +"For example, the code below creates a new variable binding `i`, which has" +" a scope throughout the entire loop and is immutable. This makes it " +"easier to write clear code and reason about it:" msgstr "" -#: ../../language/language.md:651 +#: ../../language/fundamentals.md:653 msgid "" -"A hexadecimal number has a leading zero followed by a letter \"X\", i.e. " -"`0x`/`0X`. Note that the digits after the `0x`/`0X` must be in the range " -"`0123456789ABCDEF`." +"fn main {\n" +" for i = 0; i < 5; i = i + 1 {\n" +" println(i)\n" +" }\n" +"}\n" msgstr "" -#: ../../language/language.md:654 +#: ../../language/fundamentals.md:661 msgid "" -"let hex = 0XA\n" -"let another_hex = 0xA\n" +"0\n" +"1\n" +"2\n" +"3\n" +"4\n" msgstr "" -#: ../../language/language.md:661 -msgid "Overloaded int literal" +#: ../../language/fundamentals.md:665 +msgid "The variable initialization clause can create multiple bindings:" msgstr "" -#: ../../language/language.md:663 +#: ../../language/fundamentals.md:667 msgid "" -"When the expected type is known, MoonBit can automatically overload " -"integer literal, and there is no need to specify the type of number via " -"letter postfix:" +"for i = 0, j = 0; i + j < 100; i = i + 1, j = j + 1 {\n" +" println(i)\n" +"}\n" msgstr "" -#: ../../language/language.md:665 +#: ../../language/fundamentals.md:674 msgid "" -"let int : Int = 42\n" -"let uint : UInt = 42\n" -"let int64 : Int64 = 42\n" -"let double : Double = 42\n" -"let float : Float = 42\n" -"let bigint : BigInt = 42\n" +"It should be noted that in the update clause, when there are multiple " +"binding variables, the semantics are to update them simultaneously. In " +"other words, in the example above, the update clause does not execute `i " +"= i + 1`, `j = j + 1` sequentially, but rather increments `i` and `j` at " +"the same time. Therefore, when reading the values of the binding " +"variables in the update clause, you will always get the values updated in" +" the previous iteration." msgstr "" -#: ../../language/language.md:672 -msgid "String" +#: ../../language/fundamentals.md:676 +msgid "" +"Variable initialization clauses, loop conditions, and update clauses are " +"all optional. For example, the following two are infinite loops:" msgstr "" -#: ../../language/language.md:674 +#: ../../language/fundamentals.md:678 msgid "" -"`String` holds a sequence of UTF-16 code units. You can use double quotes" -" to create a string, or use `#|` to write a multi-line string." +"for i = 1; ; i = i + 1 {\n" +" println(i)\n" +"}\n" +"for {\n" +" println(\"loop forever\")\n" +"}\n" msgstr "" -#: ../../language/language.md:676 +#: ../../language/fundamentals.md:685 msgid "" -"let a = \"兔rabbit\"\n" -"println(a[0])\n" -"println(a[1])\n" -"let b =\n" -" #| Hello\n" -" #| MoonBit\\n\n" -" #|\n" -"println(b)\n" +"The `for` loop also supports `continue`, `break`, and `else` clauses. " +"Like the `while` loop, the `for` loop can also return a value using the " +"`break` and `else` clauses." msgstr "" -#: ../../language/language.md:683 +#: ../../language/fundamentals.md:687 msgid "" -"'兔'\n" -"'r'\n" -" Hello\n" -" MoonBit\\n\n" -"\n" +"The `continue` statement skips the remaining part of the current " +"iteration of the `for` loop (including the update clause) and proceeds to" +" the next iteration. The `continue` statement can also update the binding" +" variables of the `for` loop, as long as it is followed by expressions " +"that match the number of binding variables, separated by commas." msgstr "" -#: ../../language/language.md:687 +#: ../../language/fundamentals.md:689 msgid "" -"In double quotes string, a backslash followed by certain special " -"characters forms an escape sequence:" +"For example, the following program calculates the sum of even numbers " +"from 1 to 6:" msgstr "" -#: ../../language/language.md:683 -msgid "escape sequences" +#: ../../language/fundamentals.md:691 +msgid "" +"fn main {\n" +" let sum = for i = 1, acc = 0; i <= 6; i = i + 1 {\n" +" if i % 2 == 0 {\n" +" println(\"even: \\{i}\")\n" +" continue i + 1, acc + i\n" +" }\n" +" } else {\n" +" acc\n" +" }\n" +" println(sum)\n" +"}\n" msgstr "" -#: ../../language/language.md:683 -msgid "`\\n`,`\\r`,`\\t`,`\\b`" +#: ../../language/fundamentals.md:699 +msgid "" +"even: 2\n" +"even: 4\n" +"even: 6\n" +"12\n" msgstr "" -#: ../../language/language.md:683 -msgid "New line, Carriage return, Horizontal tab, Backspace" +#: ../../language/fundamentals.md:703 +msgid "`for .. in` loop" msgstr "" -#: ../../language/language.md:683 -msgid "`\\\\`" +#: ../../language/fundamentals.md:705 +msgid "" +"MoonBit supports traversing elements of different data structures and " +"sequences via the `for .. in` loop syntax:" msgstr "" -#: ../../language/language.md:683 -msgid "Backslash" +#: ../../language/fundamentals.md:707 +msgid "" +"for x in [1, 2, 3] {\n" +" println(x)\n" +"}\n" msgstr "" -#: ../../language/language.md:683 -msgid "`\\x41`" +#: ../../language/fundamentals.md:714 +msgid "" +"`for .. in` loop is translated to the use of `Iter` in MoonBit's standard" +" library. Any type with a method `.iter() : Iter[T]` can be traversed " +"using `for .. in`. For more information of the `Iter` type, see " +"[Iterator](#iterator) below." msgstr "" -#: ../../language/language.md:683 -msgid "Hexadecimal escape sequence" +#: ../../language/fundamentals.md:717 +msgid "" +"`for .. in` loop also supports iterating through a sequence of integers, " +"such as:" msgstr "" -#: ../../language/language.md:683 -msgid "`\\o102`" +#: ../../language/fundamentals.md:719 +msgid "" +"test {\n" +" let mut i = 0\n" +" for j in 0..<10 {\n" +" i += j\n" +" }\n" +" assert_eq!(i, 45)\n" +"\n" +" let mut k = 0\n" +" for l in 0..=10 {\n" +" k += l\n" +" }\n" +" assert_eq!(k, 55)\n" +"}\n" msgstr "" -#: ../../language/language.md:683 -msgid "Octal escape sequence" +#: ../../language/fundamentals.md:726 +msgid "" +"In addition to sequences of a single value, MoonBit also supports " +"traversing sequences of two values, such as `Map`, via the `Iter2` type " +"in MoonBit's standard library. Any type with method `.iter2() : Iter2[A, " +"B]` can be traversed using `for .. in` with two loop variables:" msgstr "" -#: ../../language/language.md:683 -msgid "`\\u5154`,`\\u{1F600}`" +#: ../../language/fundamentals.md:729 +msgid "" +"for k, v in { \"x\": 1, \"y\": 2, \"z\": 3 } {\n" +" println(k)\n" +" println(v)\n" +"}\n" msgstr "" -#: ../../language/language.md:683 -msgid "Unicode escape sequence" +#: ../../language/fundamentals.md:736 +msgid "" +"Another example of `for .. in` with two loop variables is traversing an " +"array while keeping track of array index:" msgstr "" -#: ../../language/language.md:697 +#: ../../language/fundamentals.md:738 msgid "" -"MoonBit supports string interpolation. It enables you to substitute " -"variables within interpolated strings. This feature simplifies the " -"process of constructing dynamic strings by directly embedding variable " -"values into the text. Variables used for string interpolation must " -"support the `to_string` method." +"fn main {\n" +" for index, elem in [4, 5, 6] {\n" +" let i = index + 1\n" +" println(\"The \\{i}-th element of the array is \\{elem}\")\n" +" }\n" +"}\n" msgstr "" -#: ../../language/language.md:699 +#: ../../language/fundamentals.md:746 msgid "" -"let x = 42\n" -"println(\"The answer is \\{x}\")\n" +"The 1-th element of the array is 4\n" +"The 2-th element of the array is 5\n" +"The 3-th element of the array is 6\n" msgstr "" -#: ../../language/language.md:706 +#: ../../language/fundamentals.md:750 msgid "" -"Multi-line strings do not support interpolation by default, but you can " -"enable interpolation for a specific line by changing the leading `#|` to " -"`$|`:" +"Control flow operations such as `return`, `break` and error handling are " +"supported in the body of `for .. in` loop:" msgstr "" -#: ../../language/language.md:708 +#: ../../language/fundamentals.md:752 msgid "" -"let lang = \"MoonBit\"\n" -"let str =\n" -" #| Hello\n" -" #| ---\n" -" $| \\{lang}\\n\n" -" #| ---\n" -"println(str)\n" +"fn main {\n" +" let map = { \"x\": 1, \"y\": 2, \"z\": 3, \"w\": 4 }\n" +" for k, v in map {\n" +" if k == \"y\" {\n" +" continue\n" +" }\n" +" println(\"\\{k}, \\{v}\")\n" +" if k == \"z\" {\n" +" break\n" +" }\n" +" }\n" +"}\n" msgstr "" -#: ../../language/language.md:715 +#: ../../language/fundamentals.md:760 msgid "" -" Hello\n" -" ---\n" -" MoonBit\n" -"\n" -" ---\n" +"x, 1\n" +"z, 3\n" msgstr "" -#: ../../language/language.md:719 -msgid "Char" +#: ../../language/fundamentals.md:764 +msgid "If a loop variable is unused, it can be ignored with `_`." msgstr "" -#: ../../language/language.md:721 -msgid "`Char` is an integer representing a Unicode code point." +#: ../../language/fundamentals.md:766 +msgid "Functional loop" msgstr "" -#: ../../language/language.md:723 +#: ../../language/fundamentals.md:768 msgid "" -"let a : Char = 'A'\n" -"let b = '\\x41'\n" -"let c = '兔'\n" -"let zero = '\\u{30}'\n" -"let zero = '\\u0030'\n" +"Functional loop is a powerful feature in MoonBit that enables you to " +"write loops in a functional style." msgstr "" -#: ../../language/language.md:730 -msgid "Byte(s)" +#: ../../language/fundamentals.md:770 +msgid "" +"A functional loop consumes arguments and returns a value. It is defined " +"using the `loop` keyword, followed by its arguments and the loop body. " +"The loop body is a sequence of clauses, each of which consists of a " +"pattern and an expression. The clause whose pattern matches the input " +"will be executed, and the loop will return the value of the expression. " +"If no pattern matches, the loop will panic. Use the `continue` keyword " +"with arguments to start the next iteration of the loop. Use the `break` " +"keyword with arguments to return a value from the loop. The `break` " +"keyword can be omitted if the value is the last expression in the loop " +"body." msgstr "" -#: ../../language/language.md:732 +#: ../../language/fundamentals.md:772 msgid "" -"A byte literal in MoonBit is either a single ASCII character or a single " -"escape enclosed in single quotes `'`, and preceded by the character `b`. " -"Byte literals are of type `Byte`. For example:" +"test {\n" +" fn sum(xs : @immut/list.T[Int]) -> Int {\n" +" loop xs, 0 {\n" +" Nil, acc => break acc // <=> Nil, acc => acc\n" +" Cons(x, rest), acc => continue rest, x + acc\n" +" }\n" +" }\n" +"\n" +" assert_eq!(sum(Cons(1, Cons(2, Cons(3, Nil)))), 6)\n" +"}\n" msgstr "" -#: ../../language/language.md:734 +#: ../../language/fundamentals.md:779 msgid "" -"fn main {\n" -" let b1 : Byte = b'a'\n" -" println(b1.to_int())\n" -" let b2 = b'\\xff'\n" -" println(b2.to_int())\n" -"}\n" +"Currently in `loop exprs { ... }`, `exprs` is nonempty list, while `for {" +" ... }` is accepted for infinite loop." +msgstr "" + +#: ../../language/fundamentals.md:782 +msgid "Iterator" msgstr "" -#: ../../language/language.md:742 +#: ../../language/fundamentals.md:784 msgid "" -"97\n" -"255\n" +"An iterator is an object that traverse through a sequence while providing" +" access to its elements. Traditional OO languages like Java's " +"`Iterator` use `next()` `hasNext()` to step through the iteration " +"process, whereas functional languages (JavaScript's `forEach`, Lisp's " +"`mapcar`) provides a high-order function which takes an operation and a " +"sequence then consumes the sequence with that operation being applied to " +"the sequence. The former is called _external iterator_ (visible to user) " +"and the latter is called _internal iterator_ (invisible to user)." msgstr "" -#: ../../language/language.md:746 +#: ../../language/fundamentals.md:792 msgid "" -"A `Bytes` is a sequence of bytes. Similar to byte, bytes literals have " -"the form of `b\"...\"`. For example:" +"The built-in type `Iter[T]` is MoonBit's internal iterator " +"implementation. Almost all built-in sequential data structures have " +"implemented `Iter`:" msgstr "" -#: ../../language/language.md:748 +#: ../../language/fundamentals.md:795 msgid "" -"test {\n" -" let b1 : Bytes = b\"abcd\"\n" -" let b2 = b\"\\x61\\x62\\x63\\x64\"\n" -" assert_eq!(b1, b2)\n" +"fn filter_even(l : Array[Int]) -> Array[Int] {\n" +" let l_iter : Iter[Int] = l.iter()\n" +" l_iter.filter(fn { x => (x & 1) == 0 }).collect()\n" +"}\n" +"\n" +"fn fact(n : Int) -> Int {\n" +" let start = 1\n" +" let range : Iter[Int] = start.until(n)\n" +" range.fold(Int::op_mul, init=start)\n" "}\n" msgstr "" -#: ../../language/language.md:754 -msgid "Tuple" +#: ../../language/fundamentals.md:801 +msgid "Commonly used methods include:" msgstr "" -#: ../../language/language.md:756 +#: ../../language/fundamentals.md:803 msgid "" -"A tuple is a collection of finite values constructed using round brackets" -" `()` with the elements separated by commas `,`. The order of elements " -"matters; for example, `(1,true)` and `(true,1)` have different types. " -"Here's an example:" +"`each`: Iterates over each element in the iterator, applying some " +"function to each element." msgstr "" -#: ../../language/language.md:758 +#: ../../language/fundamentals.md:804 msgid "" -"fn main {\n" -" fn pack(\n" -" a : Bool,\n" -" b : Int,\n" -" c : String,\n" -" d : Double\n" -" ) -> (Bool, Int, String, Double) {\n" -" (a, b, c, d)\n" -" }\n" -"\n" -" let quad = pack(false, 100, \"text\", 3.14)\n" -" let (bool_val, int_val, str, float_val) = quad\n" -" println(\"\\{bool_val} \\{int_val} \\{str} \\{float_val}\")\n" -"}\n" -msgstr "" - -#: ../../language/language.md:766 -msgid "false 100 text 3.14\n" +"`fold`: Folds the elements of the iterator using the given function, " +"starting with the given initial value." msgstr "" -#: ../../language/language.md:770 -msgid "Tuples can be accessed via pattern matching or index:" +#: ../../language/fundamentals.md:805 +msgid "`collect`: Collects the elements of the iterator into an array." msgstr "" -#: ../../language/language.md:772 +#: ../../language/fundamentals.md:807 msgid "" -"test {\n" -" let t = (1, 2)\n" -" let (x1, y1) = t\n" -" let x2 = t.0\n" -" let y2 = t.1\n" -" assert_eq!(x1, x2)\n" -" assert_eq!(y1, y2)\n" -"}\n" +"`filter`: _lazy_ Filters the elements of the iterator based on a " +"predicate function." msgstr "" -#: ../../language/language.md:778 -msgid "Array" +#: ../../language/fundamentals.md:808 +msgid "" +"`map`: _lazy_ Transforms the elements of the iterator using a mapping " +"function." msgstr "" -#: ../../language/language.md:780 +#: ../../language/fundamentals.md:809 msgid "" -"An array is a finite sequence of values constructed using square brackets" -" `[]`, with elements separated by commas `,`. For example:" +"`concat`: _lazy_ Combines two iterators into one by appending the " +"elements of the second iterator to the first." msgstr "" -#: ../../language/language.md:782 -msgid "let numbers = [1, 2, 3, 4]\n" +#: ../../language/fundamentals.md:811 +msgid "" +"Methods like `filter` `map` are very common on a sequence object e.g. " +"Array. But what makes `Iter` special is that any method that constructs a" +" new `Iter` is _lazy_ (i.e. iteration doesn't start on call because it's " +"wrapped inside a function), as a result of no allocation for intermediate" +" value. That's what makes `Iter` superior for traversing through " +"sequence: no extra cost. MoonBit encourages user to pass an `Iter` across" +" functions instead of the sequence object itself." msgstr "" -#: ../../language/language.md:789 +#: ../../language/fundamentals.md:819 msgid "" -"You can use `numbers[x]` to refer to the xth element. The index starts " -"from zero." +"Pre-defined sequence structures like `Array` and its iterators should be " +"enough to use. But to take advantages of these methods when used with a " +"custom sequence with elements of type `S`, we will need to implement " +"`Iter`, namely, a function that returns an `Iter[S]`. Take `Bytes` as an " +"example:" msgstr "" -#: ../../language/language.md:791 +#: ../../language/fundamentals.md:824 msgid "" -"test {\n" -" let numbers = [1, 2, 3, 4]\n" -" let a = numbers[2]\n" -" numbers[3] = 5\n" -" let b = a + numbers[3]\n" -" assert_eq!(b, 8)\n" +"fn iter(data : Bytes) -> Iter[Byte] {\n" +" Iter::new(\n" +" fn(visit : (Byte) -> IterResult) -> IterResult {\n" +" for byte in data {\n" +" if visit(byte) == IterEnd {\n" +" break IterEnd\n" +" }\n" +" } else {\n" +" IterContinue\n" +" }\n" +" },\n" +" )\n" "}\n" msgstr "" -#: ../../language/language.md:798 -msgid "Map" -msgstr "" - -#: ../../language/language.md:800 +#: ../../language/fundamentals.md:830 msgid "" -"MoonBit provides a hash map data structure that preserves insertion orde " -"called `Map` in its standard library. `Map`s can be created via a " -"convenient literal syntax:" +"Almost all `Iter` implementations are identical to that of `Bytes`, the " +"only main difference being the code block that actually does the " +"iteration." msgstr "" -#: ../../language/language.md:803 -msgid "let map : Map[String, Int] = { \"x\": 1, \"y\": 2, \"z\": 3 }\n" +#: ../../language/fundamentals.md:833 +msgid "Implementation details" msgstr "" -#: ../../language/language.md:809 +#: ../../language/fundamentals.md:835 msgid "" -"Currently keys in map literal syntax must be constant. `Map`s can also be" -" destructed elegantly with pattern matching, see [Map Pattern](#map-" -"pattern)." +"The type `Iter[T]` is basically a type alias for `((T) -> IterResult) -> " +"IterResult`, a higher-order function that takes an operation and " +"`IterResult` is an enum object that tracks the state of current iteration" +" which consists any of the 2 states:" msgstr "" -#: ../../language/language.md:811 -msgid "Json literal" +#: ../../language/fundamentals.md:840 +msgid "`IterEnd`: marking the end of an iteration" msgstr "" -#: ../../language/language.md:813 +#: ../../language/fundamentals.md:841 msgid "" -"MoonBit supports convenient json handling by overloading literals. When " -"the expected type of an expression is `Json`, number, string, array and " -"map literals can be directly used to create json data:" +"`IterContinue`: marking the end of an iteration is yet to be reached, " +"implying the iteration will still continue at this state." msgstr "" -#: ../../language/language.md:816 +#: ../../language/fundamentals.md:843 msgid "" -"let moon_pkg_json_example : Json = {\n" -" \"import\": [\"moonbitlang/core/builtin\", " -"\"moonbitlang/core/coverage\"],\n" -" \"test-import\": [\"moonbitlang/core/random\"],\n" -"}\n" -msgstr "" - -#: ../../language/language.md:822 -msgid "Json values can be pattern matched too, see [Json Pattern](#json-pattern)." +"To put it simply, `Iter[T]` takes a function `(T) -> IterResult` and use " +"it to transform `Iter[T]` itself to a new state of type `IterResult`. " +"Whether that state being `IterEnd` `IterContinue` depends on the " +"function." msgstr "" -#: ../../language/language.md:824 -msgid "Variable Binding" +#: ../../language/fundamentals.md:847 +msgid "" +"Iterator provides a unified way to iterate through data structures, and " +"they can be constructed at basically no cost: as long as `fn(yield)` " +"doesn't execute, the iteration process doesn't start." msgstr "" -#: ../../language/language.md:826 +#: ../../language/fundamentals.md:851 msgid "" -"A variable can be declared as mutable or immutable using `let mut` or " -"`let`, respectively. A mutable variable can be reassigned to a new value," -" while an immutable one cannot." +"Internally a `Iter::run()` is used to trigger the iteration. Chaining all" +" sorts of `Iter` methods might be visually pleasing, but do notice the " +"heavy work underneath the abstraction." msgstr "" -#: ../../language/language.md:828 +#: ../../language/fundamentals.md:855 msgid "" -"let zero = 0\n" -"\n" -"fn main {\n" -" let mut i = 10\n" -" i = 20\n" -" println(i + zero)\n" -"}\n" +"Thus, unlike an external iterator, once the iteration starts there's no " +"way to stop unless the end is reached. Methods such as `count()` which " +"counts the number of elements in a iterator looks like an `O(1)` " +"operation but actually has linear time complexity. Carefully use " +"iterators or performance issue might occur." msgstr "" -#: ../../language/language.md:832 -msgid "Data Types" +#: ../../language/fundamentals.md:861 +msgid "Custom Data Types" msgstr "" -#: ../../language/language.md:834 +#: ../../language/fundamentals.md:863 msgid "There are two ways to create new data types: `struct` and `enum`." msgstr "" -#: ../../language/language.md:836 +#: ../../language/fundamentals.md:865 msgid "Struct" msgstr "" -#: ../../language/language.md:838 +#: ../../language/fundamentals.md:867 msgid "" "In MoonBit, structs are similar to tuples, but their fields are indexed " "by field names. A struct can be constructed using a struct literal, which" @@ -2827,7 +3252,7 @@ msgid "" "keyword `mut`, it can be assigned a new value." msgstr "" -#: ../../language/language.md:840 +#: ../../language/fundamentals.md:869 msgid "" "struct User {\n" " id : Int\n" @@ -2836,53 +3261,64 @@ msgid "" "}\n" msgstr "" -#: ../../language/language.md:846 +#: ../../language/fundamentals.md:875 msgid "" "fn main {\n" -" let u = { id: 0, name: \"John Doe\", email: \"john@doe.com\" }\n" +" let u = User::{ id: 0, name: \"John Doe\", email: \"john@doe.com\" }\n" " u.email = \"john@doe.name\"\n" +" //! u.id = 10\n" " println(u.id)\n" " println(u.name)\n" " println(u.email)\n" "}\n" msgstr "" -#: ../../language/language.md:854 +#: ../../language/fundamentals.md:883 msgid "" "0\n" "John Doe\n" "john@doe.name\n" msgstr "" -#: ../../language/language.md:858 +#: ../../language/fundamentals.md:887 msgid "Constructing Struct with Shorthand" msgstr "" -#: ../../language/language.md:860 +#: ../../language/fundamentals.md:889 msgid "" "If you already have some variable like `name` and `email`, it's redundant" " to repeat those names when constructing a struct. You can use shorthand " "instead, it behaves exactly the same:" msgstr "" -#: ../../language/language.md:862 +#: ../../language/fundamentals.md:891 msgid "" "let name = \"john\"\n" "let email = \"john@doe.com\"\n" -"let u = { id: 0, name, email }\n" +"let u = User::{ id: 0, name, email }\n" +msgstr "" + +#: ../../language/fundamentals.md:898 +msgid "" +"If there's no other struct that has the same fields, it's redundant to " +"add the struct's name when constructing it:" +msgstr "" + +#: ../../language/fundamentals.md:900 +msgid "let u2 = { id : 0, name, email }\n" msgstr "" -#: ../../language/language.md:869 +#: ../../language/fundamentals.md:907 msgid "Struct Update Syntax" msgstr "" -#: ../../language/language.md:871 +#: ../../language/fundamentals.md:909 msgid "" "It's useful to create a new struct based on an existing one, but with " "some fields updated." msgstr "" -#: ../../language/language.md:873 +#: ../../language/fundamentals.md:911 msgid "" "fn main {\n" " let user = { id: 0, name: \"John Doe\", email: \"john@doe.com\" }\n" @@ -2896,23 +3332,23 @@ msgid "" "}\n" msgstr "" -#: ../../language/language.md:881 +#: ../../language/fundamentals.md:919 msgid "" "{ id: 0, name: John Doe, email: john@doe.com }\n" "{ id: 0, name: John Doe, email: john@doe.name }\n" msgstr "" -#: ../../language/language.md:885 +#: ../../language/fundamentals.md:923 msgid "Enum" msgstr "" -#: ../../language/language.md:887 +#: ../../language/fundamentals.md:925 msgid "" "Enum types are similar to algebraic data types in functional languages. " "Users familiar with C/C++ may prefer calling it tagged union." msgstr "" -#: ../../language/language.md:889 +#: ../../language/fundamentals.md:927 msgid "" "An enum can have a set of cases (constructors). Constructor names must " "start with capitalized letter. You can use these names to construct " @@ -2920,7 +3356,7 @@ msgid "" "belongs to in pattern matching:" msgstr "" -#: ../../language/language.md:891 +#: ../../language/fundamentals.md:929 msgid "" "/// An enum type that represents the ordering relation between two " "values,\n" @@ -2932,7 +3368,7 @@ msgid "" "}\n" msgstr "" -#: ../../language/language.md:897 +#: ../../language/fundamentals.md:935 msgid "" "/// compare the ordering relation between two integers\n" "fn compare_int(x : Int, y : Int) -> Relation {\n" @@ -2965,7 +3401,7 @@ msgid "" "}\n" msgstr "" -#: ../../language/language.md:904 +#: ../../language/fundamentals.md:942 msgid "" "fn main {\n" " print_relation(compare_int(0, 1))\n" @@ -2974,20 +3410,20 @@ msgid "" "}\n" msgstr "" -#: ../../language/language.md:912 +#: ../../language/fundamentals.md:950 msgid "" "smaller!\n" "equal!\n" "greater!\n" msgstr "" -#: ../../language/language.md:916 +#: ../../language/fundamentals.md:954 msgid "" "Enum cases can also carry payload data. Here's an example of defining an " "integer list type using enum:" msgstr "" -#: ../../language/language.md:918 +#: ../../language/fundamentals.md:956 msgid "" "enum List {\n" " Nil\n" @@ -2998,7 +3434,7 @@ msgid "" "}\n" msgstr "" -#: ../../language/language.md:924 +#: ../../language/fundamentals.md:962 msgid "" "// In addition to binding payload to variables,\n" "// you can also continue matching payload data inside constructors.\n" @@ -3032,7 +3468,7 @@ msgid "" "}\n" msgstr "" -#: ../../language/language.md:931 +#: ../../language/fundamentals.md:969 msgid "" "fn main {\n" " // when creating values using `Cons`, the payload of by `Cons` must be " @@ -3043,7 +3479,7 @@ msgid "" "}\n" msgstr "" -#: ../../language/language.md:939 +#: ../../language/fundamentals.md:977 msgid "" "false\n" "1,\n" @@ -3051,15 +3487,15 @@ msgid "" "nil\n" msgstr "" -#: ../../language/language.md:943 +#: ../../language/fundamentals.md:981 msgid "Constructor with labelled arguments" msgstr "" -#: ../../language/language.md:945 +#: ../../language/fundamentals.md:983 msgid "Enum constructors can have labelled argument:" msgstr "" -#: ../../language/language.md:947 +#: ../../language/fundamentals.md:985 msgid "" "enum E {\n" " // `x` and `y` are labelled argument\n" @@ -3067,7 +3503,7 @@ msgid "" "}\n" msgstr "" -#: ../../language/language.md:953 +#: ../../language/fundamentals.md:991 msgid "" "// pattern matching constructor with labelled arguments\n" "fn f(e : E) -> Unit {\n" @@ -3081,7 +3517,7 @@ msgid "" "}\n" msgstr "" -#: ../../language/language.md:960 +#: ../../language/fundamentals.md:998 msgid "" "fn main {\n" " f(C(x=0, y=0))\n" @@ -3090,19 +3526,19 @@ msgid "" "}\n" msgstr "" -#: ../../language/language.md:968 +#: ../../language/fundamentals.md:1006 msgid "" "0!\n" "0\n" msgstr "" -#: ../../language/language.md:972 +#: ../../language/fundamentals.md:1010 msgid "" "It is also possible to access labelled arguments of constructors like " "accessing struct fields in pattern matching:" msgstr "" -#: ../../language/language.md:974 +#: ../../language/fundamentals.md:1012 msgid "" "enum Object {\n" " Point(x~ : Double, y~ : Double)\n" @@ -3130,7 +3566,7 @@ msgid "" "}\n" msgstr "" -#: ../../language/language.md:980 +#: ../../language/fundamentals.md:1018 msgid "" "fn main {\n" " let p1 : Object = Point(x=0, y=0)\n" @@ -3145,23 +3581,23 @@ msgid "" "}\n" msgstr "" -#: ../../language/language.md:988 +#: ../../language/fundamentals.md:1026 msgid "" "5\n" "NotImplementedError\n" msgstr "" -#: ../../language/language.md:992 +#: ../../language/fundamentals.md:1030 msgid "Constructor with mutable fields" msgstr "" -#: ../../language/language.md:994 +#: ../../language/fundamentals.md:1032 msgid "" "It is also possible to define mutable fields for constructor. This is " "especially useful for defining imperative data structures:" msgstr "" -#: ../../language/language.md:996 +#: ../../language/fundamentals.md:1034 msgid "" "// A set implemented using mutable binary search tree.\n" "struct Set[X] {\n" @@ -3212,15 +3648,15 @@ msgid "" "}\n" msgstr "" -#: ../../language/language.md:1002 +#: ../../language/fundamentals.md:1040 msgid "Newtype" msgstr "" -#: ../../language/language.md:1004 +#: ../../language/fundamentals.md:1042 msgid "MoonBit supports a special kind of enum called newtype:" msgstr "" -#: ../../language/language.md:1006 +#: ../../language/fundamentals.md:1044 msgid "" "// `UserId` is a fresh new type different from `Int`, \n" "// and you can define new methods for `UserId`, etc.\n" @@ -3231,7 +3667,7 @@ msgid "" "type UserName String\n" msgstr "" -#: ../../language/language.md:1012 +#: ../../language/fundamentals.md:1050 msgid "" "Newtypes are similar to enums with only one constructor (with the same " "name as the newtype itself). So, you can use the constructor to create " @@ -3239,7 +3675,7 @@ msgid "" "representation of a newtype:" msgstr "" -#: ../../language/language.md:1014 +#: ../../language/fundamentals.md:1052 msgid "" "fn main {\n" " let id : UserId = UserId(1)\n" @@ -3251,19 +3687,19 @@ msgid "" "}\n" msgstr "" -#: ../../language/language.md:1022 +#: ../../language/fundamentals.md:1060 msgid "" "1\n" "John Doe\n" msgstr "" -#: ../../language/language.md:1026 +#: ../../language/fundamentals.md:1064 msgid "" "Besides pattern matching, you can also use `._` to extract the internal " "representation of newtypes:" msgstr "" -#: ../../language/language.md:1028 +#: ../../language/fundamentals.md:1066 msgid "" "fn main {\n" " let id : UserId = UserId(1)\n" @@ -3272,19 +3708,19 @@ msgid "" "}\n" msgstr "" -#: ../../language/language.md:1036 +#: ../../language/fundamentals.md:1074 msgid "1\n" msgstr "" -#: ../../language/language.md:1040 +#: ../../language/fundamentals.md:1078 msgid "Type alias" msgstr "" -#: ../../language/language.md:1041 +#: ../../language/fundamentals.md:1079 msgid "MoonBit supports type alias via the syntax `typealias Name = TargetType`:" msgstr "" -#: ../../language/language.md:1043 +#: ../../language/fundamentals.md:1081 msgid "" "pub typealias Index = Int\n" "\n" @@ -3292,56 +3728,213 @@ msgid "" "typealias MapString[X] = Map[String, X]\n" msgstr "" -#: ../../language/language.md:1049 +#: ../../language/fundamentals.md:1087 msgid "" -"unlike all other kinds of type declaration above, type alias does not " +"Unlike all other kinds of type declaration above, type alias does not " "define a new type, it is merely a type macro that behaves exactly the " "same as its definition. So for example one cannot define new methods or " "implement traits for a type alias." msgstr "" -#: ../../language/language.md:1053 +#: ../../language/fundamentals.md:1092 +msgid "Type alias can be used to perform incremental code refactor." +msgstr "" + +#: ../../language/fundamentals.md:1094 +msgid "" +"For example, if you want to move a type `T` from `@pkgA` to `@pkgB`, you " +"can leave a type alias `typealias T = @pkgB.T` in `@pkgA`, and " +"**incrementally** port uses of `@pkgA.T` to `@pkgB.T`. The type alias can" +" be removed after all uses of `@pkgA.T` is migrated to `@pkgB.T`." +msgstr "" + +#: ../../language/fundamentals.md:1099 +msgid "Local types" +msgstr "" + +#: ../../language/fundamentals.md:1101 +msgid "" +"Moonbit supports declaring structs/enums/newtypes at the top of a " +"toplevel function, which are only visible within the current toplevel " +"function. These local types can use the generic parameters of the " +"toplevel function but cannot introduce additional generic parameters " +"themselves. Local types can derive methods using derive, but no " +"additional methods can be defined manually. For example:" +msgstr "" + +#: ../../language/fundamentals.md:1108 +msgid "" +"fn toplevel[T: Show](x: T) -> Unit {\n" +" enum LocalEnum {\n" +" A(T)\n" +" B(Int)\n" +" } derive(Show)\n" +" struct LocalStruct {\n" +" a: (String, T)\n" +" } derive(Show)\n" +" type LocalNewtype T derive(Show)\n" +" ...\n" +"}\n" +msgstr "" + +#: ../../language/fundamentals.md:1114 +msgid "Currently, local types do not support being declared as error types." +msgstr "" + +#: ../../language/fundamentals.md:1116 +msgid "Pattern Matching" +msgstr "" + +#: ../../language/fundamentals.md:1118 +msgid "" +"Pattern matching allows us to match on specific pattern and bind data " +"from data structures." +msgstr "" + +#: ../../language/fundamentals.md:1120 +msgid "Simple Patterns" +msgstr "" + +#: ../../language/fundamentals.md:1122 +msgid "We can pattern match expressions against" +msgstr "" + +#: ../../language/fundamentals.md:1124 +msgid "literals, such as boolean values, numbers, chars, strings, etc" +msgstr "" + +#: ../../language/fundamentals.md:1125 +msgid "constants" +msgstr "" + +#: ../../language/fundamentals.md:1126 +msgid "structs" +msgstr "" + +#: ../../language/fundamentals.md:1127 +msgid "enums" +msgstr "" + +#: ../../language/fundamentals.md:1128 +msgid "arrays" +msgstr "" + +#: ../../language/fundamentals.md:1129 +msgid "maps" +msgstr "" + +#: ../../language/fundamentals.md:1130 +msgid "JSONs" +msgstr "" + +#: ../../language/fundamentals.md:1132 +msgid "" +"and so on. We can define identifiers to bind the matched values so that " +"they can be used later." +msgstr "" + +#: ../../language/fundamentals.md:1134 +msgid "" +"const ONE = 1\n" +"\n" +"fn match_int(x : Int) -> Unit {\n" +" match x {\n" +" 0 => println(\"zero\")\n" +" ONE => println(\"one\")\n" +" value => println(value)\n" +" }\n" +"}\n" +msgstr "" + +#: ../../language/fundamentals.md:1141 +msgid "" +"We can use `_` as wildcards for the values we don't care about, and use " +"`..` to ignore remaining fields of struct or enum, or array (see [array " +"pattern](#array-pattern))." +msgstr "" + +#: ../../language/fundamentals.md:1143 +msgid "" +"struct Point3D {\n" +" x : Int\n" +" y : Int\n" +" z : Int\n" +"}\n" +"\n" +"fn match_point3D(p : Point3D) -> Unit {\n" +" match p {\n" +" { x: 0, .. } => println(\"on yz-plane\")\n" +" _ => println(\"not on yz-plane\")\n" +" }\n" +"}\n" +"\n" +"enum Point[T] {\n" +" Point2D(Int, Int, name~: String, payload~ : T)\n" +"}\n" +"\n" +"fn match_point[T](p : Point[T]) -> Unit {\n" +" match p {\n" +" //! Point2D(0, 0) => println(\"2D origin\")\n" +" Point2D(0, 0, ..) => println(\"2D origin\")\n" +" Point2D(_) => println(\"2D point\")\n" +" _ => panic()\n" +" }\n" +"}\n" +msgstr "" + +#: ../../language/fundamentals.md:1150 +msgid "" +"We can use `as` to give a name to some pattern, and we can use `|` to " +"match several cases at once. A variable name can only be bound once in a " +"single pattern, and the same set of variables should be bound on both " +"sides of `|` patterns." +msgstr "" + +#: ../../language/fundamentals.md:1152 +msgid "" +"match expr {\n" +" //! Add(e1, e2) | Lit(e1) => ...\n" +" Lit(n) as a => ...\n" +" Add(e1, e2) | Mul(e1, e2) => ...\n" +" _ => ...\n" +"}\n" +msgstr "" + +#: ../../language/fundamentals.md:1159 +msgid "Array Pattern" +msgstr "" + +#: ../../language/fundamentals.md:1161 msgid "" -"Type alias can be used to perform incremental code refactor. For example," -" if you want to move a type `T` from `@pkgA` to `@pkgB`, you can leave a " -"type alias `typealias T = @pkgB.T` in `@pkgA`, and **incrementally** port" -" uses of `@pkgA.T` to `@pkgB.T`. The type alias can be removed after all " -"uses of `@pkgA.T` is migrated to `@pkgB.T`." +"For `Array`, `FixedArray` and `ArrayView`, MoonBit allows using array " +"pattern." +msgstr "" + +#: ../../language/fundamentals.md:1163 +msgid "Array pattern have the following forms:" +msgstr "" + +#: ../../language/fundamentals.md:1165 +msgid "`[]` : matching for an empty data structure" msgstr "" -#: ../../language/language.md:1058 -msgid "Pattern Matching" +#: ../../language/fundamentals.md:1166 +msgid "`[pa, pb, pc]` : matching for known number of elements, 3 in this example" msgstr "" -#: ../../language/language.md:1060 +#: ../../language/fundamentals.md:1167 msgid "" -"We have shown a use case of pattern matching for enums, but pattern " -"matching is not restricted to enums. For example, we can also match " -"expressions against Boolean values, numbers, characters, strings, tuples," -" arrays, and struct literals. Since there is only one case for those " -"types other than enums, we can pattern match them using `let` binding " -"instead of `match` expressions. Note that the scope of bound variables in" -" `match` is limited to the case where the variable is introduced, while " -"`let` binding will introduce every variable to the current scope. " -"Furthermore, we can use underscores `_` as wildcards for the values we " -"don't care about, use `..` to ignore remaining fields of struct or " -"elements of array." +"`[pa, ..]` : matching for known number of elements, followed by unknown " +"number of elements" msgstr "" -#: ../../language/language.md:1062 +#: ../../language/fundamentals.md:1168 msgid "" -"let id = match u {\n" -" { id, name: _, email: _ } => id\n" -"}\n" -"\n" -"// <=>\n" -"let { id, name: _, email: _ } = u\n" -"\n" -"// <=>\n" -"let { id, .. } = u\n" +"`[.., pa]` : matching for known number of elements, preceded by unknown " +"number of elements" msgstr "" -#: ../../language/language.md:1069 +#: ../../language/fundamentals.md:1170 msgid "" "test {\n" " let ary = [1, 2, 3, 4]\n" @@ -3352,53 +3945,40 @@ msgid "" "}\n" msgstr "" -#: ../../language/language.md:1075 -msgid "" -"There are some other useful constructs in pattern matching. For example, " -"we can use `as` to give a name to some pattern, and we can use `|` to " -"match several cases at once. A variable name can only be bound once in a " -"single pattern, and the same set of variables should be bound on both " -"sides of `|` patterns." +#: ../../language/fundamentals.md:1176 +msgid "Range Pattern" msgstr "" -#: ../../language/language.md:1077 +#: ../../language/fundamentals.md:1177 msgid "" -"match expr {\n" -" Lit(n) as a => ...\n" -" Add(e1, e2) | Mul(e1, e2) => ...\n" -" _ => ...\n" -"}\n" -msgstr "" - -#: ../../language/language.md:1084 -msgid "Range Pattern" +"For builtin integer types and `Char`, MoonBit allows matching whether the" +" value falls in a specific range." msgstr "" -#: ../../language/language.md:1085 +#: ../../language/fundamentals.md:1179 msgid "" -"For builtin integer types and `Char`, MoonBit allows matching whether the" -" value falls in a specific range. Range patterns have the form `a.. Option[V]` for some type `K` and `V`." +"`op_get(Self, K) -> Option[V]` for some type `K` and `V` (see [method and" +" trait](./methods.md))." msgstr "" -#: ../../language/language.md:1116 -msgid "Currently, the key part of map pattern must be a constant" +#: ../../language/fundamentals.md:1209 +msgid "Currently, the key part of map pattern must be a literal or constant" msgstr "" -#: ../../language/language.md:1117 +#: ../../language/fundamentals.md:1210 msgid "Map patterns are always open: unmatched keys are silently ignored" msgstr "" -#: ../../language/language.md:1118 +#: ../../language/fundamentals.md:1211 msgid "" "Map pattern will be compiled to efficient code: every key will be fetched" " at most once" msgstr "" -#: ../../language/language.md:1120 +#: ../../language/fundamentals.md:1213 msgid "Json Pattern" msgstr "" -#: ../../language/language.md:1122 +#: ../../language/fundamentals.md:1215 msgid "" "When the matched value has type `Json`, literal patterns can be used " -"directly:" +"directly, together with constructors:" msgstr "" -#: ../../language/language.md:1124 +#: ../../language/fundamentals.md:1217 msgid "" "match json {\n" " { \"version\": \"1.0.0\", \"import\": [..] as imports } => ...\n" +" { \"version\": Number(i), \"import\": Array(imports)} => ...\n" " _ => ...\n" "}\n" msgstr "" -#: ../../language/language.md:1131 -msgid "Operators" -msgstr "" - -#: ../../language/language.md:1133 -msgid "Operator Overloading" +#: ../../language/fundamentals.md:1224 +msgid "Generics" msgstr "" -#: ../../language/language.md:1135 +#: ../../language/fundamentals.md:1226 msgid "" -"MoonBit supports operator overloading of builtin operators via methods. " -"The method name corresponding to a operator `` is `op_`. For " -"example:" +"Generics are supported in top-level function and data type definitions. " +"Type parameters can be introduced within square brackets. We can rewrite " +"the aforementioned data type `List` to add a type parameter `T` to obtain" +" a generic version of lists. We can then define generic functions over " +"lists like `map` and `reduce`." msgstr "" -#: ../../language/language.md:1137 +#: ../../language/fundamentals.md:1228 msgid "" -"struct T {\n" -" x : Int\n" -"}\n" -"\n" -"fn op_add(self : T, other : T) -> T {\n" -" { x: self.x + other.x }\n" -"}\n" -"\n" -"test {\n" -" let a = { x: 0 }\n" -" let b = { x: 2 }\n" -" assert_eq!((a + b).x, 2)\n" +"enum List[T] {\n" +" Nil\n" +" Cons(T, List[T])\n" "}\n" -msgstr "" - -#: ../../language/language.md:1143 -msgid "Another example about `op_get` and `op_set`:" -msgstr "" - -#: ../../language/language.md:1145 -msgid "" -"struct Coord {\n" -" mut x : Int\n" -" mut y : Int\n" -"} derive(Show)\n" "\n" -"fn op_get(self : Coord, key : String) -> Int {\n" -" match key {\n" -" \"x\" => self.x\n" -" \"y\" => self.y\n" +"fn map[S, T](self : List[S], f : (S) -> T) -> List[T] {\n" +" match self {\n" +" Nil => Nil\n" +" Cons(x, xs) => Cons(f(x), map(xs, f))\n" " }\n" "}\n" "\n" -"fn op_set(self : Coord, key : String, val : Int) -> Unit {\n" -" match key {\n" -" \"x\" => self.x = val\n" -" \"y\" => self.y = val\n" +"fn reduce[S, T](self : List[S], op : (T, S) -> T, init : T) -> T {\n" +" match self {\n" +" Nil => init\n" +" Cons(x, xs) => reduce(xs, op, op(init, x))\n" " }\n" "}\n" msgstr "" -#: ../../language/language.md:1151 -msgid "" -"fn main {\n" -" let c = { x: 1, y: 2 }\n" -" println(c)\n" -" println(c[\"y\"])\n" -" c[\"x\"] = 23\n" -" println(c)\n" -" println(c[\"x\"])\n" -"}\n" -msgstr "" - -#: ../../language/language.md:1159 -msgid "" -"{x: 1, y: 2}\n" -"2\n" -"{x: 23, y: 2}\n" -"23\n" -msgstr "" - -#: ../../language/language.md:1163 -msgid "Currently, the following operators can be overloaded:" -msgstr "" - -#: ../../language/language.md:1159 -msgid "Operator Name" -msgstr "" - -#: ../../language/language.md:1159 -msgid "Method Name" -msgstr "" - -#: ../../language/language.md:1159 -msgid "`+`" -msgstr "" - -#: ../../language/language.md:1159 -msgid "`op_add`" -msgstr "" - -#: ../../language/language.md:1159 -msgid "`-`" -msgstr "" - -#: ../../language/language.md:1159 -msgid "`op_sub`" -msgstr "" - -#: ../../language/language.md:1159 -msgid "`*`" -msgstr "" - -#: ../../language/language.md:1159 -msgid "`op_mul`" -msgstr "" - -#: ../../language/language.md:1159 -msgid "`/`" -msgstr "" - -#: ../../language/language.md:1159 -msgid "`op_div`" -msgstr "" - -#: ../../language/language.md:1159 -msgid "`%`" -msgstr "" - -#: ../../language/language.md:1159 -msgid "`op_mod`" -msgstr "" - -#: ../../language/language.md:1159 -msgid "`=`" -msgstr "" - -#: ../../language/language.md:1159 -msgid "`op_equal`" -msgstr "" - -#: ../../language/language.md:1159 ../../language/language.md:1222 -msgid "`<<`" -msgstr "" - -#: ../../language/language.md:1159 ../../language/language.md:1222 -msgid "`op_shl`" -msgstr "" - -#: ../../language/language.md:1159 ../../language/language.md:1222 -msgid "`>>`" -msgstr "" - -#: ../../language/language.md:1159 ../../language/language.md:1222 -msgid "`op_shr`" -msgstr "" - -#: ../../language/language.md:1159 -msgid "`-` (unary)" -msgstr "" - -#: ../../language/language.md:1159 -msgid "`op_neg`" -msgstr "" - -#: ../../language/language.md:1159 -msgid "`_[_]` (get item)" -msgstr "" - -#: ../../language/language.md:1159 -msgid "`op_get`" -msgstr "" - -#: ../../language/language.md:1159 -msgid "`_[_] = _` (set item)" -msgstr "" - -#: ../../language/language.md:1159 -msgid "`op_set`" -msgstr "" - -#: ../../language/language.md:1159 -msgid "`_[_:_]` (view)" -msgstr "" - -#: ../../language/language.md:1159 -msgid "`op_as_view`" +#: ../../language/fundamentals.md:1232 +msgid "Special Syntax" msgstr "" -#: ../../language/language.md:1180 +#: ../../language/fundamentals.md:1234 msgid "Pipe operator" msgstr "" -#: ../../language/language.md:1182 +#: ../../language/fundamentals.md:1236 msgid "" "MoonBit provides a convenient pipe operator `|>`, which can be used to " "chain regular function calls:" msgstr "" -#: ../../language/language.md:1184 +#: ../../language/fundamentals.md:1238 msgid "" "5 |> ignore // <=> ignore(5)\n" "[] |> push(5) // <=> push([], 5)\n" @@ -3689,25 +4124,25 @@ msgid "" "|> ignore // <=> ignore(add(1, 5))\n" msgstr "" -#: ../../language/language.md:1191 +#: ../../language/fundamentals.md:1245 msgid "Cascade Operator" msgstr "" -#: ../../language/language.md:1193 +#: ../../language/fundamentals.md:1247 msgid "" "The cascade operator `..` is used to perform a series of mutable " "operations on the same value consecutively. The syntax is as follows:" msgstr "" -#: ../../language/language.md:1196 +#: ../../language/fundamentals.md:1250 msgid "x..f()\n" msgstr "" -#: ../../language/language.md:1203 +#: ../../language/fundamentals.md:1257 msgid "`x..f()..g()` is equivalent to `{x.f(); x.g(); x}`." msgstr "" -#: ../../language/language.md:1205 +#: ../../language/fundamentals.md:1259 msgid "" "Consider the following scenario: for a `StringBuilder` type that has " "methods like `write_string`, `write_char`, `write_object`, etc., we often" @@ -3715,7 +4150,7 @@ msgid "" "value:" msgstr "" -#: ../../language/language.md:1209 +#: ../../language/fundamentals.md:1263 msgid "" "let builder = StringBuilder::new()\n" "builder.write_char('a')\n" @@ -3725,7 +4160,7 @@ msgid "" "let result = builder.to_string()\n" msgstr "" -#: ../../language/language.md:1216 +#: ../../language/fundamentals.md:1270 msgid "" "To avoid repetitive typing of `builder`, its methods are often designed " "to return `self` itself, allowing operations to be chained using the `.` " @@ -3735,7 +4170,7 @@ msgid "" " the methods." msgstr "" -#: ../../language/language.md:1222 +#: ../../language/fundamentals.md:1276 msgid "" "let result = StringBuilder::new()\n" " ..write_char('a')\n" @@ -3745,538 +4180,365 @@ msgid "" " .to_string()\n" msgstr "" -#: ../../language/language.md:1229 -msgid "Bitwise Operator" +#: ../../language/fundamentals.md:1283 +msgid "TODO syntax" msgstr "" -#: ../../language/language.md:1231 -msgid "MoonBit supports C-Style bitwise operators." +#: ../../language/fundamentals.md:1285 +msgid "" +"The `todo` syntax (`...`) is a special construct used to mark sections of" +" code that are not yet implemented or are placeholders for future " +"functionality. For example:" msgstr "" -#: ../../language/language.md:1222 -msgid "Operator" +#: ../../language/fundamentals.md:1287 +msgid "" +"fn todo_in_func() -> Int {\n" +" ...\n" +"}\n" msgstr "" -#: ../../language/language.md:1222 -msgid "Perform" +#: ../../language/index.md:1 +msgid "MoonBit Language" msgstr "" -#: ../../language/language.md:1222 -msgid "`&`" +#: ../../language/index.md:3 +msgid "" +"MoonBit is an end-to-end programming language toolchain for cloud and " +"edge computing using WebAssembly. The IDE environment is available at " +"[https://try.moonbitlang.com](https://try.moonbitlang.com) without any " +"installation; it does not rely on any server either." msgstr "" -#: ../../language/language.md:1222 -msgid "`land`" +#: ../../language/index.md:5 +msgid "**Status and aimed timeline**" msgstr "" -#: ../../language/language.md:1222 -msgid "`|`" +#: ../../language/index.md:7 +msgid "MoonBit is currently in beta-preview. We expect to reach 1.0 in 2025." msgstr "" -#: ../../language/language.md:1222 -msgid "`lor`" +#: ../../language/index.md:9 +msgid "" +"When MoonBit reaches beta, it means any backwards-incompatible changes " +"will be seriously evaluated and MoonBit _can_ be used in production(very " +"rare compiler bugs). MoonBit is developed by a talented full time team " +"who had extensive experience in building language toolchains, so we will " +"grow much faster than the typical language ecosystem, you won't wait long" +" to use MoonBit in your production." msgstr "" -#: ../../language/language.md:1222 -msgid "`^`" +#: ../../language/index.md:11 +msgid "**Main advantages**" msgstr "" -#: ../../language/language.md:1222 -msgid "`lxor`" +#: ../../language/index.md:13 +msgid "Generate significantly smaller WASM output than any existing solutions." msgstr "" -#: ../../language/language.md:1241 -msgid "Error Handling" +#: ../../language/index.md:14 +msgid "Much faster runtime performance." msgstr "" -#: ../../language/language.md:1243 -msgid "Error types" +#: ../../language/index.md:15 +msgid "State of the art compile-time performance." msgstr "" -#: ../../language/language.md:1245 -msgid "" -"The error values used in MoonBit must have an error type. An error type " -"can be defined in the following forms:" +#: ../../language/index.md:16 +msgid "Simple but practical, data-oriented language design." msgstr "" -#: ../../language/language.md:1248 -msgid "" -"type! E1 Int // error type E1 has one constructor E1 with an Int payload\n" -"\n" -"type! E2 // error type E2 has one constructor E2 with no payload\n" -"\n" -"type! E3 { // error type E3 has three constructors like a normal enum " -"type\n" -" A\n" -" B(Int, x~ : String)\n" -" C(mut x~ : String, Char, y~ : Bool)\n" -"}\n" +#: ../../language/introduction.md:1 +msgid "Introduction" msgstr "" -#: ../../language/language.md:1255 -msgid "" -"The return type of a function can include an error type to indicate that " -"the function might return an error. For example, the following function " -"`div` might return an error of type `DivError`:" +#: ../../language/introduction.md:3 +msgid "A MoonBit program consists of top-level definitions including:" msgstr "" -#: ../../language/language.md:1259 -msgid "" -"type! DivError String\n" -"\n" -"fn div(x : Int, y : Int) -> Int!DivError {\n" -" if y == 0 {\n" -" raise DivError(\"division by zero\")\n" -" }\n" -" x / y\n" -"}\n" +#: ../../language/introduction.md:5 +msgid "type definitions" msgstr "" -#: ../../language/language.md:1266 -msgid "" -"Here, the keyword `raise` is used to interrupt the function execution and" -" return an error." +#: ../../language/introduction.md:6 +msgid "function definitions" msgstr "" -#: ../../language/language.md:1269 -msgid "The Default Error Type" +#: ../../language/introduction.md:7 +msgid "constant definitions and variable bindings" msgstr "" -#: ../../language/language.md:1271 -msgid "" -"MoonBit provides a default error type `Error` that can be used when the " -"concrete error type is not important. For convenience, you can annotate " -"the function name or the return type with the suffix `!` to indicate that" -" the `Error` type is used. For example, the following function signatures" -" are equivalent:" +#: ../../language/introduction.md:8 +msgid "`init` functions, `main` function and/or `test` blocks." msgstr "" -#: ../../language/language.md:1276 -msgid "" -"fn f() -> Unit! {\n" -" ...\n" -"}\n" -"\n" -"fn g!() -> Unit {\n" -" ...\n" -"}\n" -"\n" -"fn h() -> Unit!Error {\n" -" ...\n" -"}\n" +#: ../../language/introduction.md:10 +msgid "Expressions and Statements" msgstr "" -#: ../../language/language.md:1283 +#: ../../language/introduction.md:12 msgid "" -"For anonymous function and matrix function, you can annotate the keyword " -"`fn` with the `!` suffix to achieve that. For example," +"MoonBit distinguishes between statements and expressions. In a function " +"body, only the last clause should be an expression, which serves as a " +"return value. For example:" msgstr "" -#: ../../language/language.md:1286 +#: ../../language/introduction.md:14 msgid "" -"type! IntError Int\n" -"\n" -"fn h(f : (Int) -> Int!, x : Int) -> Unit {\n" -" ...\n" +"fn foo() -> Int {\n" +" let x = 1\n" +" x + 1\n" "}\n" "\n" -"fn g() -> Unit {\n" -" let _ = h(fn! { x => raise IntError(x) }, 0)\n" -" let _ = h(fn!(x) { raise IntError(x) }, 0)\n" -"\n" +"fn bar() -> Int {\n" +" let x = 1\n" +" //! x + 1\n" +" x + 2\n" "}\n" msgstr "" -#: ../../language/language.md:1292 -msgid "" -"As shown in the above example, the error types defined by `type!` can be " -"used as value of the type `Error` when the error is raised." +#: ../../language/introduction.md:20 +msgid "Expressions include:" msgstr "" -#: ../../language/language.md:1295 +#: ../../language/introduction.md:22 msgid "" -"Note that only error types or the type `Error` can be used as errors. For" -" functions that are generic in the error type, you can use the `Error` " -"bound to do that. For example," +"Value literals (e.g. Boolean values, numbers, characters, strings, " +"arrays, tuples, structs)" msgstr "" -#: ../../language/language.md:1299 -msgid "" -"// Result::unwrap_or_error\n" -"fn unwrap_or_error[T, E : Error](result : Result[T, E]) -> T!E {\n" -" match result {\n" -" Ok(x) => x\n" -" Err(e) => raise e\n" -" }\n" -"}\n" +#: ../../language/introduction.md:23 +msgid "Arithmetical, logical, or comparison operations" msgstr "" -#: ../../language/language.md:1305 +#: ../../language/introduction.md:24 msgid "" -"Since the type `Error` can include multiple error types, pattern matching" -" on the `Error` type must use the wildcard `_` to match all error types. " -"For example," +"Accesses to array elements (e.g. `a[0]`), struct fields (e.g `r.x`), " +"tuple components (e.g. `t.0`), etc." msgstr "" -#: ../../language/language.md:1308 -msgid "" -"type! E4\n" -"\n" -"type! E5\n" -"\n" -"fn f(e : Error) -> Unit {\n" -" match e {\n" -" E4 => println(\"E1\")\n" -" E5 => println(\"E2\")\n" -" _ => println(\"unknown error\")\n" -" }\n" -"}\n" +#: ../../language/introduction.md:25 +msgid "Variables and (capitalized) enum constructors" msgstr "" -#: ../../language/language.md:1314 -msgid "Handling Errors" +#: ../../language/introduction.md:26 +msgid "Anonymous local function definitions" msgstr "" -#: ../../language/language.md:1316 -msgid "There are three ways to handle errors:" +#: ../../language/introduction.md:27 +msgid "`match`, `if`, `loop` expressions, etc." msgstr "" -#: ../../language/language.md:1318 -msgid "" -"Append `!` after the function name in a function application to rethrow " -"the error directly in case of an error, for example:" +#: ../../language/introduction.md:29 +msgid "Statements include:" msgstr "" -#: ../../language/language.md:1321 -msgid "" -"fn div_reraise(x : Int, y : Int) -> Int!DivError {\n" -" div!(x, y) // Rethrow the error if `div` raised an error\n" -"}\n" +#: ../../language/introduction.md:31 +msgid "Named local function definitions" msgstr "" -#: ../../language/language.md:1327 -msgid "" -"Append `?` after the function name to convert the result into a first-" -"class value of the `Result` type, for example:" +#: ../../language/introduction.md:32 +msgid "Local variable bindings" msgstr "" -#: ../../language/language.md:1330 -msgid "" -"test {\n" -" let res = div?(6, 3)\n" -" inspect!(res, content=\"Ok(2)\")\n" -" let res = div?(6, 0)\n" -" inspect!(\n" -" res,\n" -" content=\n" -" #|Err(\"division by zero\")\n" -" ,\n" -" )\n" -"}\n" +#: ../../language/introduction.md:33 +msgid "Assignments" msgstr "" -#: ../../language/language.md:1336 -msgid "Use `try` and `catch` to catch and handle errors, for example:" +#: ../../language/introduction.md:34 +msgid "`return` statements" +msgstr "" + +#: ../../language/introduction.md:35 +msgid "Any expression whose return type is `Unit`, (e.g. `ignore`)" msgstr "" -#: ../../language/language.md:1338 +#: ../../language/introduction.md:37 msgid "" -"fn main {\n" -"try {\n" -" div!(42, 0)\n" -"} catch {\n" -" DivError(s) => println(s)\n" -"} else {\n" -" v => println(v)\n" -"}\n" -"}\n" +"A code block can contain multiple statements and one expression, and the " +"value of the expression is the value of the code block." msgstr "" -#: ../../language/language.md:1347 -#, fuzzy -msgid "division by zero\n" -msgstr "示例:除零" +#: ../../language/introduction.md:39 +msgid "Variable Binding" +msgstr "" -#: ../../language/language.md:1351 +#: ../../language/introduction.md:41 msgid "" -"Here, `try` is used to call a function that might throw an error, and " -"`catch` is used to match and handle the caught error. If no error is " -"caught, the catch block will not be executed and the `else` block will be" -" executed instead." +"A variable can be declared as mutable or immutable using `let mut` or " +"`let`, respectively. A mutable variable can be reassigned to a new value," +" while an immutable one cannot." msgstr "" -#: ../../language/language.md:1355 -msgid "" -"The `else` block can be omitted if no action is needed when no error is " -"caught. For example:" +#: ../../language/introduction.md:43 +msgid "A constant can only be declared at top level and cannot be changed." msgstr "" -#: ../../language/language.md:1358 +#: ../../language/introduction.md:45 msgid "" -"try {\n" -" println(div!(42, 0))\n" -"} catch {\n" -" _ => println(\"Error\")\n" +"let zero = 0\n" +"\n" +"const ZERO = 0\n" +"\n" +"fn main {\n" +" //! const ZERO = 0 \n" +" let mut i = 10\n" +" i = 20\n" +" println(i + zero + ZERO)\n" "}\n" msgstr "" -#: ../../language/language.md:1365 -msgid "" -"The `catch` keyword is optional, and when the body of `try` is a simple " -"expression, the curly braces can be omitted. For example:" +#: ../../language/introduction.md:50 +msgid "A top level variable binding" msgstr "" -#: ../../language/language.md:1368 +#: ../../language/introduction.md:51 msgid "" -"let a = try {\n" -" div!(42, 0)\n" -"} catch {\n" -" _ => 0\n" -"}\n" -"println(a)\n" +"requires **explicit** type annotation (unless defined using literals such" +" as string, byte or numbers)" msgstr "" -#: ../../language/language.md:1375 -msgid "" -"The `!` and `?` attributes can also be used on method invocation and pipe" -" operator. For example:" +#: ../../language/introduction.md:52 +msgid "can't be mutable (use `Ref` instead)" msgstr "" -#: ../../language/language.md:1378 -msgid "" -"type T Int\n" -"\n" -"type! E Int derive(Show)\n" -"\n" -"fn k(self : T) -> Unit!E {\n" -" ...\n" -"}\n" -"\n" -"fn l() -> Unit!E {\n" -" let x = T(42)\n" -" k!(x)\n" -" x.k!()\n" -" x |> k!()\n" -"}\n" +#: ../../language/introduction.md:56 +msgid "Naming conventions" msgstr "" -#: ../../language/language.md:1384 +#: ../../language/introduction.md:58 msgid "" -"However for infix operators such as `+` `*` that may raise an error, the " -"original form has to be used, e.g. `x.op_add!(y)`, `x.op_mul!(y)`." +"Variables, functions should start with lowercase letters `a-z` and can " +"contain letters, numbers, and other non-ascii unicode chars. It is " +"recommended to name them with snake_case." msgstr "" -#: ../../language/language.md:1387 +#: ../../language/introduction.md:61 msgid "" -"Additionally, if the return type of a function includes an error type, " -"the function call must use `!` or `?` for error handling, otherwise the " -"compiler will report an error." +"Constants, types should start with uppercase letters `A-Z` and can " +"contain letters, numbers, and other non-ascii unicode chars. It is " +"recommended to name them with PascalCase or SCREAMING_SNAKE_CASE." msgstr "" -#: ../../language/language.md:1391 -msgid "Error Inference" +#: ../../language/introduction.md:64 +msgid "Program entrance" msgstr "" -#: ../../language/language.md:1393 -msgid "" -"Within a `try` block, several different kinds of errors can be raised. " -"When that happens, the compiler will use the type `Error` as the common " -"error type. Accordingly, the handler must use the wildcard `_` to make " -"sure all errors are caught. For example," +#: ../../language/introduction.md:66 +msgid "`init` and `main`" msgstr "" -#: ../../language/language.md:1398 +#: ../../language/introduction.md:67 msgid "" -"fn f1() -> Unit!E1 {\n" -" ...\n" -"}\n" -"\n" -"fn f2() -> Unit!E2 {\n" -" ...\n" -"}\n" -"\n" -"try {\n" -" f1!()\n" -" f2!()\n" -"} catch {\n" -" E1(_) => ...\n" -" E2 => ...\n" -" _ => ...\n" -"}\n" +"There is a specialized function called `init` function. The `init` " +"function is special:" msgstr "" -#: ../../language/language.md:1405 -msgid "" -"You can also use `catch!` to rethrow the uncaught errors for convenience." -" This is useful when you only want to handle a specific error and rethrow" -" others. For example," +#: ../../language/introduction.md:69 +msgid "It has no parameter list nor return type." msgstr "" -#: ../../language/language.md:1409 -msgid "" -"try {\n" -" f1!()\n" -" f2!()\n" -"} catch! {\n" -" E1(_) => ...\n" -"}\n" +#: ../../language/introduction.md:70 +msgid "There can be multiple `init` functions in the same package." msgstr "" -#: ../../language/language.md:1416 -msgid "Generics" +#: ../../language/introduction.md:71 +msgid "" +"An `init` function can't be explicitly called or referred to by other " +"functions. Instead, all `init` functions will be implicitly called when " +"initializing a package. Therefore, `init` functions should only consist " +"of statements." msgstr "" -#: ../../language/language.md:1418 +#: ../../language/introduction.md:74 msgid "" -"Generics are supported in top-level function and data type definitions. " -"Type parameters can be introduced within square brackets. We can rewrite " -"the aforementioned data type `List` to add a type parameter `T` to obtain" -" a generic version of lists. We can then define generic functions over " -"lists like `map` and `reduce`." +"fn init {\n" +" let x = 1\n" +" println(x)\n" +"}\n" msgstr "" -#: ../../language/language.md:1420 +#: ../../language/introduction.md:80 msgid "" -"enum List[T] {\n" -" Nil\n" -" Cons(T, List[T])\n" -"}\n" -"\n" -"fn map[S, T](self : List[S], f : (S) -> T) -> List[T] {\n" -" match self {\n" -" Nil => Nil\n" -" Cons(x, xs) => Cons(f(x), map(xs, f))\n" -" }\n" -"}\n" -"\n" -"fn reduce[S, T](self : List[S], op : (T, S) -> T, init : T) -> T {\n" -" match self {\n" -" Nil => init\n" -" Cons(x, xs) => reduce(xs, op, op(init, x))\n" -" }\n" -"}\n" +"There is another specialized function called `main` function. The `main` " +"function is the main entrance of the program, and it will be executed " +"after the initialization stage." msgstr "" -#: ../../language/language.md:1424 -msgid "Access Control" +#: ../../language/introduction.md:82 +msgid "Same as the `init` function, it has no parameter list nor return type." msgstr "" -#: ../../language/language.md:1426 +#: ../../language/introduction.md:84 msgid "" -"By default, all function definitions and variable bindings are " -"_invisible_ to other packages. You can use the `pub` modifier before " -"toplevel `let`/`fn` to make them public." +"fn main {\n" +" let x = 2\n" +" println(x)\n" +"}\n" msgstr "" -#: ../../language/language.md:1429 -msgid "There are four different kinds of visibility for types in MoonBit:" +#: ../../language/introduction.md:90 +msgid "The previous two code snippets will print the following at runtime:" msgstr "" -#: ../../language/language.md:1431 +#: ../../language/introduction.md:92 msgid "" -"private type, declared with `priv`, completely invisible to the outside " -"world" +"1\n" +"2\n" msgstr "" -#: ../../language/language.md:1432 +#: ../../language/introduction.md:97 msgid "" -"abstract type, which is the default visibility for types. Only the name " -"of an abstract type is visible outside, the internal representation of " -"the type is hidden" +"Only packages that are `main` packages can define such `main` function. " +"Check out [build system tutorial](/toolchain/moon/tutorial) for detail." msgstr "" -#: ../../language/language.md:1433 -msgid "" -"readonly types, declared with `pub(readonly)`. The internal " -"representation of readonly types are visible outside, but users can only " -"read the values of these types from outside, construction and mutation " -"are not allowed" +#: ../../language/introduction.md:99 +msgid "moon.pkg.json" msgstr "" -#: ../../language/language.md:1435 +#: ../../language/introduction.md:99 msgid "" -"fully public types, declared with `pub(all)`. The outside world can " -"freely construct, modify and read values of these types" +"{\n" +" \"is-main\": true\n" +"}" msgstr "" -#: ../../language/language.md:1437 -msgid "" -"Currently, the semantic of `pub` is `pub(all)`. But in the future, the " -"meaning of `pub` will be ported to `pub(readonly)`. In addition to the " -"visibility of the type itself, the fields of a public `struct` can be " -"annotated with `priv`, which will hide the field from the outside world " -"completely. Note that `struct`s with private fields cannot be constructed" -" directly outside, but you can update the public fields using the " -"functional struct update syntax." +#: ../../language/introduction.md:104 +msgid "`test`" msgstr "" -#: ../../language/language.md:1443 +#: ../../language/introduction.md:106 msgid "" -"Readonly types is a very useful feature, inspired by [private " -"types](https://v2.ocaml.org/manual/privatetypes.html) in OCaml. In short," -" values of `pub(readonly)` types can be destructed by pattern matching " -"and the dot syntax, but cannot be constructed or mutated in other " -"packages. Note that there is no restriction within the same package where" -" `pub(readonly)` types are defined." +"There's also a top-level structure called `test` block. A `test` block " +"defines inline tests, such as:" msgstr "" -#: ../../language/language.md:1447 +#: ../../language/introduction.md:108 ../../language/tests.md:11 msgid "" -"// Package A\n" -"pub(readonly) struct RO {\n" -" field: Int\n" -"}\n" -"test {\n" -" let r = { field: 4 } // OK\n" -" let r = { ..r, field: 8 } // OK\n" -"}\n" -"\n" -"// Package B\n" -"fn println(r : RO) -> Unit {\n" -" println(\"{ field: \")\n" -" println(r.field) // OK\n" -" println(\" }\")\n" -"}\n" -"test {\n" -" let r : RO = { field: 4 } // ERROR: Cannot create values of the public" -" read-only type RO!\n" -" let r = { ..r, field: 8 } // ERROR: Cannot mutate a public read-only " -"field!\n" +"test \"test_name\" {\n" +" assert_eq!(1 + 1, 2)\n" +" assert_eq!(2 + 2, 4)\n" +" inspect!([1, 2, 3], content=\"[1, 2, 3]\")\n" "}\n" msgstr "" -#: ../../language/language.md:1469 +#: ../../language/introduction.md:114 msgid "" -"Access control in MoonBit adheres to the principle that a `pub` type, " -"function, or variable cannot be defined in terms of a private type. This " -"is because the private type may not be accessible everywhere that the " -"`pub` entity is used. MoonBit incorporates sanity checks to prevent the " -"occurrence of use cases that violate this principle." +"The following contents will use `test` block and `main` function to " +"demonstrate the execution result, and we assume that all the `test` " +"blocks pass unless stated otherwise." msgstr "" -#: ../../language/language.md:1472 -msgid "" -"pub struct S {\n" -" x: T1 // OK\n" -" y: T2 // OK\n" -" z: T3 // ERROR: public field has private type `T3`!\n" -"}\n" -"\n" -"// ERROR: public function has private parameter type `T3`!\n" -"pub fn f1(_x: T3) -> T1 { T1::A(0) }\n" -"// ERROR: public function has private return type `T3`!\n" -"pub fn f2(_x: T1) -> T3 { T3::A(0) }\n" -"// OK\n" -"pub fn f3(_x: T1) -> T1 { T1::A(0) }\n" -"\n" -"pub let a: T3 // ERROR: public variable has private type `T3`!\n" +#: ../../language/methods.md:1 +msgid "Method and Trait" msgstr "" -#: ../../language/language.md:1489 +#: ../../language/methods.md:3 msgid "Method system" msgstr "" -#: ../../language/language.md:1491 +#: ../../language/methods.md:5 msgid "" "MoonBit supports methods in a different way from traditional object-" "oriented languages. A method in MoonBit is just a toplevel function " @@ -4284,57 +4546,57 @@ msgid "" "syntax `fn TypeName::method_name(...) -> ...`:" msgstr "" -#: ../../language/language.md:1493 ../../language/language.md:1535 +#: ../../language/methods.md:7 msgid "" -"pub(all) enum List[X] {\n" +"enum List[X] {\n" " Nil\n" " Cons(X, List[X])\n" "}\n" "\n" -"pub fn List::concat[X](xs : List[List[X]]) -> List[X] {\n" +"fn List::concat[X](xs : List[List[X]]) -> List[X] {\n" " ...\n" "}\n" msgstr "" -#: ../../language/language.md:1499 +#: ../../language/methods.md:13 msgid "" "As a convenient shorthand, when the first parameter of a function is " "named `self`, MoonBit automatically defines the function as a method of " "the type of `self`:" msgstr "" -#: ../../language/language.md:1501 +#: ../../language/methods.md:15 msgid "" "fn List::map[X, Y](xs : List[X], f : (X) -> Y) -> List[Y] {\n" " ...\n" "}\n" msgstr "" -#: ../../language/language.md:1507 +#: ../../language/methods.md:21 msgid "is equivalent to:" msgstr "" -#: ../../language/language.md:1509 +#: ../../language/methods.md:23 msgid "" "fn map[X, Y](self : List[X], f : (X) -> Y) -> List[Y] {\n" " ...\n" "}\n" msgstr "" -#: ../../language/language.md:1515 +#: ../../language/methods.md:29 msgid "" "Methods are just regular functions owned by a type constructor. So when " "there is no ambiguity, methods can be called using regular function call " "syntax directly:" msgstr "" -#: ../../language/language.md:1517 +#: ../../language/methods.md:31 msgid "" "let xs : List[List[_]] = { ... }\n" "let ys = concat(xs)\n" msgstr "" -#: ../../language/language.md:1524 +#: ../../language/methods.md:38 msgid "" "Unlike regular functions, methods support overloading: different types " "can define methods of the same name. If there are multiple methods of the" @@ -4342,7 +4604,7 @@ msgid "" " explicitly adding a `TypeName::` prefix:" msgstr "" -#: ../../language/language.md:1526 +#: ../../language/methods.md:40 msgid "" "struct T1 {\n" " x1 : Int\n" @@ -4368,7 +4630,7 @@ msgid "" "}\n" msgstr "" -#: ../../language/language.md:1533 +#: ../../language/methods.md:47 msgid "" "When the first parameter of a method is also the type it belongs to, " "methods can be called using dot syntax `x.method(...)`. MoonBit " @@ -4376,11 +4638,23 @@ msgid "" " no need to write the type name and even the package name of the method:" msgstr "" -#: ../../language/language.md:1541 +#: ../../language/methods.md:49 +msgid "" +"pub(all) enum List[X] {\n" +" Nil\n" +" Cons(X, List[X])\n" +"}\n" +"\n" +"pub fn List::concat[X](xs : List[List[X]]) -> List[X] {\n" +" ...\n" +"}\n" +msgstr "" + +#: ../../language/methods.md:55 msgid "using package with alias list" msgstr "" -#: ../../language/language.md:1541 +#: ../../language/methods.md:55 msgid "" "fn f() -> Unit {\n" " let xs : @list.List[@list.List[Unit]] = Nil\n" @@ -4391,43 +4665,225 @@ msgid "" "}\n" msgstr "" -#: ../../language/language.md:1549 +#: ../../language/methods.md:63 msgid "" "The highlighted line is only possible when there is no ambiguity in " "`@list`." msgstr "" -#: ../../language/language.md:1551 -msgid "View" +#: ../../language/methods.md:65 +msgid "Operator Overloading" msgstr "" -#: ../../language/language.md:1553 +#: ../../language/methods.md:67 msgid "" -"Analogous to `slice` in other languages, the view is a reference to a " -"specific segment of collections. You can use `data[start:end]` to create " -"a view of array `data`, referencing elements from `start` to `end` " -"(exclusive). Both `start` and `end` indices can be omitted." +"MoonBit supports operator overloading of builtin operators via methods. " +"The method name corresponding to a operator `` is `op_`. For " +"example:" msgstr "" -#: ../../language/language.md:1558 +#: ../../language/methods.md:69 msgid "" +"struct T {\n" +" x : Int\n" +"}\n" +"\n" +"fn op_add(self : T, other : T) -> T {\n" +" { x: self.x + other.x }\n" +"}\n" +"\n" "test {\n" -" let xs = [0, 1, 2, 3, 4, 5]\n" -" let s1 : ArrayView[Int] = xs[2:]\n" -" inspect!(s1, content=\"[2, 3, 4, 5]\")\n" -" inspect!(xs[:4], content=\"[0, 1, 2, 3]\")\n" -" inspect!(xs[2:5], content=\"[2, 3, 4]\")\n" -" inspect!(xs[:], content=\"[0, 1, 2, 3, 4, 5]\")\n" +" let a = { x: 0 }\n" +" let b = { x: 2 }\n" +" assert_eq!((a + b).x, 2)\n" +"}\n" +msgstr "" + +#: ../../language/methods.md:75 +msgid "Another example about `op_get` and `op_set`:" +msgstr "" + +#: ../../language/methods.md:77 +msgid "" +"struct Coord {\n" +" mut x : Int\n" +" mut y : Int\n" +"} derive(Show)\n" +"\n" +"fn op_get(self : Coord, key : String) -> Int {\n" +" match key {\n" +" \"x\" => self.x\n" +" \"y\" => self.y\n" +" }\n" +"}\n" +"\n" +"fn op_set(self : Coord, key : String, val : Int) -> Unit {\n" +" match key {\n" +" \"x\" => self.x = val\n" +" \"y\" => self.y = val\n" +" }\n" +"}\n" +msgstr "" + +#: ../../language/methods.md:83 +msgid "" +"fn main {\n" +" let c = { x: 1, y: 2 }\n" +" println(c)\n" +" println(c[\"y\"])\n" +" c[\"x\"] = 23\n" +" println(c)\n" +" println(c[\"x\"])\n" "}\n" msgstr "" -#: ../../language/language.md:1564 +#: ../../language/methods.md:91 +msgid "" +"{x: 1, y: 2}\n" +"2\n" +"{x: 23, y: 2}\n" +"23\n" +msgstr "" + +#: ../../language/methods.md:95 +msgid "Currently, the following operators can be overloaded:" +msgstr "" + +#: ../../language/methods.md:91 +msgid "Operator Name" +msgstr "" + +#: ../../language/methods.md:91 +msgid "Method Name" +msgstr "" + +#: ../../language/methods.md:91 +msgid "`+`" +msgstr "" + +#: ../../language/methods.md:91 +msgid "`op_add`" +msgstr "" + +#: ../../language/methods.md:91 +msgid "`-`" +msgstr "" + +#: ../../language/methods.md:91 +msgid "`op_sub`" +msgstr "" + +#: ../../language/methods.md:91 +msgid "`*`" +msgstr "" + +#: ../../language/methods.md:91 +msgid "`op_mul`" +msgstr "" + +#: ../../language/methods.md:91 +msgid "`/`" +msgstr "" + +#: ../../language/methods.md:91 +msgid "`op_div`" +msgstr "" + +#: ../../language/methods.md:91 +msgid "`%`" +msgstr "" + +#: ../../language/methods.md:91 +msgid "`op_mod`" +msgstr "" + +#: ../../language/methods.md:91 +msgid "`=`" +msgstr "" + +#: ../../language/methods.md:91 +msgid "`op_equal`" +msgstr "" + +#: ../../language/methods.md:91 +msgid "`<<`" +msgstr "" + +#: ../../language/methods.md:91 +msgid "`op_shl`" +msgstr "" + +#: ../../language/methods.md:91 +msgid "`>>`" +msgstr "" + +#: ../../language/methods.md:91 +msgid "`op_shr`" +msgstr "" + +#: ../../language/methods.md:91 +msgid "`-` (unary)" +msgstr "" + +#: ../../language/methods.md:91 +msgid "`op_neg`" +msgstr "" + +#: ../../language/methods.md:91 +msgid "`_[_]` (get item)" +msgstr "" + +#: ../../language/methods.md:91 +msgid "`op_get`" +msgstr "" + +#: ../../language/methods.md:91 +msgid "`_[_] = _` (set item)" +msgstr "" + +#: ../../language/methods.md:91 +msgid "`op_set`" +msgstr "" + +#: ../../language/methods.md:91 +msgid "`_[_:_]` (view)" +msgstr "" + +#: ../../language/methods.md:91 +msgid "`op_as_view`" +msgstr "" + +#: ../../language/methods.md:91 +msgid "`&`" +msgstr "" + +#: ../../language/methods.md:91 +msgid "`land`" +msgstr "" + +#: ../../language/methods.md:91 +msgid "`|`" +msgstr "" + +#: ../../language/methods.md:91 +msgid "`lor`" +msgstr "" + +#: ../../language/methods.md:91 +msgid "`^`" +msgstr "" + +#: ../../language/methods.md:91 +msgid "`lxor`" +msgstr "" + +#: ../../language/methods.md:118 msgid "" -"By implementing `op_as_view` method, you can also create a view for a " -"user-defined type. Here is an example:" +"By implementing `op_as_view` method, you can create a view for a user-" +"defined type. Here is an example:" msgstr "" -#: ../../language/language.md:1566 +#: ../../language/methods.md:120 msgid "" "type DataView String\n" "\n" @@ -4447,39 +4903,92 @@ msgid "" "}\n" msgstr "" -#: ../../language/language.md:1572 +#: ../../language/methods.md:126 msgid "Trait system" msgstr "" -#: ../../language/language.md:1574 +#: ../../language/methods.md:128 +msgid "" +"MoonBit features a structural trait system for overloading/ad-hoc " +"polymorphism. Traits declare a list of operations, which must be supplied" +" when a type wants to implement the trait. Traits can be declared as " +"follows:" +msgstr "" + +#: ../../language/methods.md:130 +msgid "" +"trait I {\n" +" method_(Int) -> Int\n" +" method_with_label(Int, label~: Int) -> Int\n" +" //! method_with_label(Int, label?: Int) -> Int\n" +"}\n" +msgstr "" + +#: ../../language/methods.md:136 +msgid "" +"In the body of a trait definition, a special type `Self` is used to refer" +" to the type that implements the trait." +msgstr "" + +#: ../../language/methods.md:138 +msgid "Extending traits" +msgstr "" + +#: ../../language/methods.md:140 +msgid "A trait can depend on other traits, for example:" +msgstr "" + +#: ../../language/methods.md:142 +msgid "" +"trait Position {\n" +" pos(Self) -> (Int, Int)\n" +"}\n" +"trait Draw {\n" +" draw(Self) -> Unit\n" +"}\n" +"\n" +"trait Object : Position + Draw {}\n" +msgstr "" + +#: ../../language/methods.md:148 +msgid "" +"To implement the super trait, one will have to implement the sub traits," +" and the methods defined in the super trait." +msgstr "" + +#: ../../language/methods.md:151 +msgid "Implementing traits" +msgstr "" + +#: ../../language/methods.md:153 msgid "" -"MoonBit features a structural trait system for overloading/ad-hoc " -"polymorphism. Traits declare a list of operations, which must be supplied" -" when a type wants to implement the trait. Traits can be declared as " -"follows:" +"To implement a trait, a type must provide all the methods required by the" +" trait." msgstr "" -#: ../../language/language.md:1576 +#: ../../language/methods.md:155 msgid "" -"trait I {\n" -" method_(Int) -> Int\n" -"}\n" +"This allows types to implement a trait implicitly, hence allowing " +"different packages to work together without seeing or depending on each " +"other. For example, the following trait is automatically implemented for " +"builtin number types such as `Int` and `Double`:" msgstr "" -#: ../../language/language.md:1582 +#: ../../language/methods.md:158 msgid "" -"In the body of a trait definition, a special type `Self` is used to refer" -" to the type that implements the trait." +"trait Number {\n" +" op_add(Self, Self) -> Self\n" +" op_mul(Self, Self) -> Self\n" +"}\n" msgstr "" -#: ../../language/language.md:1584 +#: ../../language/methods.md:164 msgid "" -"To implement a trait, a type must provide all the methods required by the" -" trait. Implementation for trait methods can be provided via the syntax " -"`impl Trait for Type with method_name(...) { ... }`, for example:" +"**Explicit implementation** for trait methods can be provided via the " +"syntax `impl Trait for Type with method_name(...) { ... }`, for example:" msgstr "" -#: ../../language/language.md:1587 +#: ../../language/methods.md:166 msgid "" "trait MyShow {\n" " to_string(Self) -> String\n" @@ -4497,20 +5006,20 @@ msgid "" "impl[X : MyShow] MyShow for MyContainer[X] with to_string(self) { ... }\n" msgstr "" -#: ../../language/language.md:1593 +#: ../../language/methods.md:172 msgid "" "Type annotation can be omitted for trait `impl`: MoonBit will " "automatically infer the type based on the signature of `Trait::method` " "and the self type." msgstr "" -#: ../../language/language.md:1595 +#: ../../language/methods.md:174 msgid "" -"The author of the trait can also define default implementations for some " -"methods in the trait, for example:" +"The author of the trait can also define **default implementations** for " +"some methods in the trait, for example:" msgstr "" -#: ../../language/language.md:1597 +#: ../../language/methods.md:176 msgid "" "trait J {\n" " f(Self) -> Unit\n" @@ -4523,7 +5032,7 @@ msgid "" "}\n" msgstr "" -#: ../../language/language.md:1603 +#: ../../language/methods.md:182 msgid "" "Implementers of trait `I` don't have to provide an implementation for " "`f_twice`: to implement `I`, only `f` is necessary. They can always " @@ -4531,46 +5040,38 @@ msgid "" "with f_twice`, if desired, though." msgstr "" -#: ../../language/language.md:1606 +#: ../../language/methods.md:185 msgid "" "If an explicit `impl` or default implementation is not found, trait " -"method resolution falls back to regular methods. This allows types to " -"implement a trait implicitly, hence allowing different packages to work " -"together without seeing or depending on each other. For example, the " -"following trait is automatically implemented for builtin number types " -"such as `Int` and `Double`:" +"method resolution falls back to regular methods." msgstr "" -#: ../../language/language.md:1610 -msgid "" -"trait Number {\n" -" op_add(Self, Self) -> Self\n" -" op_mul(Self, Self) -> Self\n" -"}\n" +#: ../../language/methods.md:187 +msgid "Using traits" msgstr "" -#: ../../language/language.md:1616 +#: ../../language/methods.md:189 msgid "" "When declaring a generic function, the type parameters can be annotated " "with the traits they should implement, allowing the definition of " "constrained generic functions. For example:" msgstr "" -#: ../../language/language.md:1618 +#: ../../language/methods.md:191 msgid "" "fn square[N : Number](x : N) -> N {\n" " x * x // <=> x.op_mul(x)\n" "}\n" msgstr "" -#: ../../language/language.md:1624 +#: ../../language/methods.md:197 msgid "" "Without the `Number` requirement, the expression `x * x` in `square` will" " result in a method/operator not found error. Now, the function `square` " "can be called with any type that implements `Number`, for example:" msgstr "" -#: ../../language/language.md:1626 +#: ../../language/methods.md:199 msgid "" "struct Point {\n" " x : Int\n" @@ -4592,11 +5093,205 @@ msgid "" "}\n" msgstr "" -#: ../../language/language.md:1632 +#: ../../language/methods.md:205 +msgid "Invoke trait methods directly" +msgstr "" + +#: ../../language/methods.md:207 +msgid "" +"Methods of a trait can be called directly via `Trait::method`. MoonBit " +"will infer the type of `Self` and check if `Self` indeed implements " +"`Trait`, for example:" +msgstr "" + +#: ../../language/methods.md:209 +msgid "" +"test {\n" +" assert_eq!(Show::to_string(42), \"42\")\n" +" assert_eq!(Compare::compare(1.0, 2.5), -1)\n" +"}\n" +msgstr "" + +#: ../../language/methods.md:215 +msgid "" +"Trait implementations can also be invoked via dot syntax, with the " +"following restrictions:" +msgstr "" + +#: ../../language/methods.md:217 +msgid "" +"if a regular method is present, the regular method is always favored when" +" using dot syntax" +msgstr "" + +#: ../../language/methods.md:218 +msgid "" +"only trait implementations that are located in the package of the self " +"type can be invoked via dot syntax" +msgstr "" + +#: ../../language/methods.md:219 +msgid "" +"if there are multiple trait methods (from different traits) with the same" +" name available, an ambiguity error is reported" +msgstr "" + +#: ../../language/methods.md:220 +msgid "" +"if neither of the above two rules apply, trait `impl`s in current package" +" will also be searched for dot syntax. This allows extending a foreign " +"type locally." +msgstr "" + +#: ../../language/methods.md:222 +msgid "" +"these `impl`s can only be called via dot syntax locally, even if they are" +" public." +msgstr "" + +#: ../../language/methods.md:224 +msgid "" +"The above rules ensures that MoonBit's dot syntax enjoys good property " +"while being flexible. For example, adding a new dependency never break " +"existing code with dot syntax due to ambiguity. These rules also make " +"name resolution of MoonBit extremely simple: the method called via dot " +"syntax must always come from current package or the package of the type!" +msgstr "" + +#: ../../language/methods.md:229 +msgid "Here's an example of calling trait `impl` with dot syntax:" +msgstr "" + +#: ../../language/methods.md:231 +msgid "" +"struct MyCustomType {}\n" +"\n" +"impl Show for MyCustomType with output(self, logger) { ... }\n" +"\n" +"fn f() -> Unit {\n" +" let x = MyCustomType::{ }\n" +" let _ = x.to_string()\n" +"\n" +"}\n" +msgstr "" + +#: ../../language/methods.md:237 +msgid "Trait objects" +msgstr "" + +#: ../../language/methods.md:239 +msgid "" +"MoonBit supports runtime polymorphism via trait objects. If `t` is of " +"type `T`, which implements trait `I`, one can pack the methods of `T` " +"that implements `I`, together with `t`, into a runtime object via `t as " +"&I`. Trait object erases the concrete type of a value, so objects created" +" from different concrete types can be put in the same data structure and " +"handled uniformly:" +msgstr "" + +#: ../../language/methods.md:246 +msgid "" +"trait Animal {\n" +" speak(Self) -> String\n" +"}\n" +"\n" +"type Duck String\n" +"\n" +"fn Duck::make(name : String) -> Duck {\n" +" Duck(name)\n" +"}\n" +"\n" +"fn speak(self : Duck) -> String {\n" +" \"\\{self._}: quack!\"\n" +"}\n" +"\n" +"type Fox String\n" +"\n" +"fn Fox::make(name : String) -> Fox {\n" +" Fox(name)\n" +"}\n" +"\n" +"fn Fox::speak(_self : Fox) -> String {\n" +" \"What does the fox say?\"\n" +"}\n" +"\n" +"test {\n" +" let duck1 = Duck::make(\"duck1\")\n" +" let duck2 = Duck::make(\"duck2\")\n" +" let fox1 = Fox::make(\"fox1\")\n" +" let animals : Array[&Animal] = [\n" +" duck1 as &Animal,\n" +" duck2 as &Animal,\n" +" fox1 as &Animal,\n" +" ]\n" +" inspect!(\n" +" animals.map(fn(animal) { animal.speak() }),\n" +" content=\n" +" #|[\"duck1: quack!\", \"duck2: quack!\", \"What does the fox " +"say?\"]\n" +" ,\n" +" )\n" +"}\n" +msgstr "" + +#: ../../language/methods.md:252 +msgid "" +"Not all traits can be used to create objects. \"object-safe\" traits' " +"methods must satisfy the following conditions:" +msgstr "" + +#: ../../language/methods.md:255 +msgid "`Self` must be the first parameter of a method" +msgstr "" + +#: ../../language/methods.md:256 +msgid "" +"There must be only one occurrence of `Self` in the type of the method " +"(i.e. the first parameter)" +msgstr "" + +#: ../../language/methods.md:258 +msgid "" +"Users can define new methods for trait objects, just like defining new " +"methods for structs and enums:" +msgstr "" + +#: ../../language/methods.md:260 +msgid "" +"trait Logger {\n" +" write_string(Self, String) -> Unit\n" +"}\n" +"\n" +"trait CanLog {\n" +" log(Self, &Logger) -> Unit\n" +"}\n" +"\n" +"fn &Logger::write_object[Obj : CanLog](self : &Logger, obj : Obj) -> Unit" +" {\n" +" obj.log(self)\n" +"}\n" +"\n" +"// use the new method to simplify code\n" +"impl[A : CanLog, B : CanLog] CanLog for (A, B) with log(self, logger) {\n" +" let (a, b) = self\n" +" logger\n" +" ..write_string(\"(\")\n" +" ..write_object(a)\n" +" ..write_string(\", \")\n" +" ..write_object(b)\n" +" .write_string(\")\")\n" +"}\n" +msgstr "" + +#: ../../language/methods.md:266 +msgid "Builtin traits" +msgstr "" + +#: ../../language/methods.md:268 msgid "MoonBit provides the following useful builtin traits:" msgstr "" -#: ../../language/language.md:1636 +#: ../../language/methods.md:272 msgid "" "trait Eq {\n" " op_equal(Self, Self) -> Bool\n" @@ -4608,13 +5303,13 @@ msgid "" "}\n" "\n" "trait Hash {\n" -" hash(Self) -> Int\n" +" hash_combine(Self, Hasher) -> Unit // to be implemented\n" +" hash(Self) -> Int // has default implementation\n" "}\n" "\n" "trait Show {\n" -" // writes a string representation of `Self` into a `Logger`\n" -" output(Self, Logger) -> Unit\n" -" to_string(Self) -> String\n" +" output(Self, Logger) -> Unit // to be implemented\n" +" to_string(Self) -> String // has default implementation\n" "}\n" "\n" "trait Default {\n" @@ -4622,93 +5317,225 @@ msgid "" "}\n" msgstr "" -#: ../../language/language.md:1661 -msgid "Invoke trait methods directly" +#: ../../language/methods.md:297 +msgid "Deriving builtin traits" msgstr "" -#: ../../language/language.md:1662 -msgid "" -"Methods of a trait can be called directly via `Trait::method`. MoonBit " -"will infer the type of `Self` and check if `Self` indeed implements " -"`Trait`, for example:" +#: ../../language/methods.md:299 +msgid "MoonBit can automatically derive implementations for some builtin traits:" msgstr "" -#: ../../language/language.md:1664 +#: ../../language/methods.md:301 msgid "" +"struct T {\n" +" x : Int\n" +" y : Int\n" +"} derive(Eq, Compare, Show, Default)\n" +"\n" "test {\n" -" assert_eq!(Show::to_string(42), \"42\")\n" -" assert_eq!(Compare::compare(1.0, 2.5), -1)\n" +" let t1 = T::default()\n" +" let t2 = T::{ x: 1, y: 1 }\n" +" inspect!(t1, content=\"{x: 0, y: 0}\")\n" +" inspect!(t2, content=\"{x: 1, y: 1}\")\n" +" assert_not_eq!(t1, t2)\n" +" assert_true!(t1 < t2)\n" "}\n" msgstr "" -#: ../../language/language.md:1670 +#: ../../language/packages.md:1 +msgid "Managing Projects with Packages" +msgstr "" + +#: ../../language/packages.md:3 msgid "" -"Trait implementations can also be invoked via dot syntax, with the " -"following restrictions:" +"When developing projects at large scale, the project usually needs to be " +"divided into smaller modular unit that depends on each other. More " +"often, it involves using other people's work: most noticeably is the " +"[core](https://github.com/moonbitlang/core), the standard library of " +"MoonBit." +msgstr "" + +#: ../../language/packages.md:6 +msgid "Packages and modules" +msgstr "" + +#: ../../language/packages.md:8 +msgid "" +"In MoonBit, the most important unit for code organization is a package, " +"which consists of a number of source code files and a single " +"`moon.pkg.json` configuration file. A package can either be a `main` " +"package, consisting a `main` function, or a package that serves as a " +"library." +msgstr "" + +#: ../../language/packages.md:11 +msgid "" +"A project, corresponding to a module, consists of multiple packages and a" +" single `moon.mod.json` configuration file." +msgstr "" + +#: ../../language/packages.md:13 +msgid "" +"When using things from another package, the dependency between modules " +"should first be declared inside the `moon.mod.json`. The dependency " +"between packages should then be declared inside the `moon.pkg.json`. Then" +" it is possible to use `@pkg` to access the imported entities, where " +"`pkg` is the last part of the imported package's path or the declared " +"alias in `moon.pkg.json`:" +msgstr "" + +#: ../../language/packages.md:17 +msgid "pkgB/moon.pkg.json" +msgstr "" + +#: ../../language/packages.md:17 +msgid "" +"{\n" +" \"import\": [\n" +" \"moonbit-community/language/packages/pkgA\"\n" +" ]\n" +"}" +msgstr "" + +#: ../../language/packages.md:22 +msgid "pkgB/top.mbt" +msgstr "" + +#: ../../language/packages.md:22 +msgid "" +"pub fn add1(x : Int) -> Int {\n" +" @pkgA.incr(x)\n" +"}" +msgstr "" + +#: ../../language/packages.md:27 +msgid "Access Control" +msgstr "" + +#: ../../language/packages.md:29 +msgid "" +"By default, all function definitions and variable bindings are " +"_invisible_ to other packages. You can use the `pub` modifier before " +"toplevel `let`/`fn` to make them public." +msgstr "" + +#: ../../language/packages.md:32 +msgid "There are four different kinds of visibility for types in MoonBit:" +msgstr "" + +#: ../../language/packages.md:34 +msgid "" +"private type, declared with `priv`, completely invisible to the outside " +"world" +msgstr "" + +#: ../../language/packages.md:35 +msgid "" +"abstract type, which is the default visibility for types. Only the name " +"of an abstract type is visible outside, the internal representation of " +"the type is hidden" msgstr "" -#: ../../language/language.md:1672 +#: ../../language/packages.md:36 msgid "" -"if a regular method is present, the regular method is always favored when" -" using dot syntax" +"readonly types, declared with `pub(readonly)`. The internal " +"representation of readonly types are visible outside, but users can only " +"read the values of these types from outside, construction and mutation " +"are not allowed" msgstr "" -#: ../../language/language.md:1673 +#: ../../language/packages.md:38 msgid "" -"only trait implementations that are located in the package of the self " -"type can be invoked via dot syntax" +"fully public types, declared with `pub(all)`. The outside world can " +"freely construct, modify and read values of these types" msgstr "" -#: ../../language/language.md:1674 +#: ../../language/packages.md:41 msgid "" -"if there are multiple trait methods (from different traits) with the same" -" name available, an ambiguity error is reported" +"Currently, the semantic of `pub` is `pub(all)`. But in the future, the " +"meaning of `pub` will be ported to `pub(readonly)`." msgstr "" -#: ../../language/language.md:1675 +#: ../../language/packages.md:44 msgid "" -"if neither of the above two rules apply, trait `impl`s in current package" -" will also be searched for dot syntax. This allows extending a foreign " -"type locally." +"In addition to the visibility of the type itself, the fields of a public " +"`struct` can be annotated with `priv`, which will hide the field from the" +" outside world completely. Note that `struct`s with private fields cannot" +" be constructed directly outside, but you can update the public fields " +"using the functional struct update syntax." msgstr "" -#: ../../language/language.md:1677 +#: ../../language/packages.md:49 msgid "" -"these `impl`s can only be called via dot syntax locally, even if they are" -" public." +"Readonly types is a very useful feature, inspired by [private " +"types](https://v2.ocaml.org/manual/privatetypes.html) in OCaml. In short," +" values of `pub(readonly)` types can be destructed by pattern matching " +"and the dot syntax, but cannot be constructed or mutated in other " +"packages. Note that there is no restriction within the same package where" +" `pub(readonly)` types are defined." msgstr "" -#: ../../language/language.md:1679 +#: ../../language/packages.md:53 msgid "" -"The above rules ensures that MoonBit's dot syntax enjoys good property " -"while being flexible. For example, adding a new dependency never break " -"existing code with dot syntax due to ambiguity. These rules also make " -"name resolution of MoonBit extremely simple: the method called via dot " -"syntax must always come from current package or the package of the type!" +"// Package A\n" +"pub(readonly) struct RO {\n" +" field: Int\n" +"}\n" +"test {\n" +" let r = { field: 4 } // OK\n" +" let r = { ..r, field: 8 } // OK\n" +"}\n" +"\n" +"// Package B\n" +"fn println(r : RO) -> Unit {\n" +" println(\"{ field: \")\n" +" println(r.field) // OK\n" +" println(\" }\")\n" +"}\n" +"test {\n" +" let r : RO = { field: 4 } // ERROR: Cannot create values of the public" +" read-only type RO!\n" +" let r = { ..r, field: 8 } // ERROR: Cannot mutate a public read-only " +"field!\n" +"}\n" msgstr "" -#: ../../language/language.md:1684 -msgid "Here's an example of calling trait `impl` with dot syntax:" +#: ../../language/packages.md:75 +msgid "" +"Access control in MoonBit adheres to the principle that a `pub` type, " +"function, or variable cannot be defined in terms of a private type. This " +"is because the private type may not be accessible everywhere that the " +"`pub` entity is used. MoonBit incorporates sanity checks to prevent the " +"occurrence of use cases that violate this principle." msgstr "" -#: ../../language/language.md:1686 +#: ../../language/packages.md:78 msgid "" -"struct MyCustomType {}\n" +"pub(all) type T1\n" +"pub(all) type T2\n" +"priv type T3\n" "\n" -"impl Show for MyCustomType with output(self, logger) { ... }\n" +"pub(all) struct S {\n" +" x: T1 // OK\n" +" y: T2 // OK\n" +" z: T3 // ERROR: public field has private type `T3`!\n" +"}\n" "\n" -"fn f() -> Unit {\n" -" let x = MyCustomType::{ }\n" -" let _ = x.to_string()\n" +"// ERROR: public function has private parameter type `T3`!\n" +"pub fn f1(_x: T3) -> T1 { ... }\n" +"// ERROR: public function has private return type `T3`!\n" +"pub fn f2(_x: T1) -> T3 { ... }\n" +"// OK\n" +"pub fn f3(_x: T1) -> T1 { ... }\n" "\n" -"}\n" +"pub let a: T3 = { ... } // ERROR: public variable has private type `T3`!\n" msgstr "" -#: ../../language/language.md:1692 +#: ../../language/packages.md:99 msgid "Access control of methods and trait implementations" msgstr "" -#: ../../language/language.md:1694 +#: ../../language/packages.md:101 msgid "" "To make the trait system coherent (i.e. there is a globally unique " "implementation for every `Type: Trait` pair), and prevent third-party " @@ -4717,32 +5544,32 @@ msgid "" "methods/implement traits for types:" msgstr "" -#: ../../language/language.md:1698 +#: ../../language/packages.md:105 msgid "" "_only the package that defines a type can define methods for it_. So one " "cannot define new methods or override old methods for builtin and foreign" " types." msgstr "" -#: ../../language/language.md:1699 +#: ../../language/packages.md:106 msgid "" "_only the package of the type or the package of the trait can define an " "implementation_. For example, only `@pkg1` and `@pkg2` are allowed to " "write `impl @pkg1.Trait for @pkg2.Type`." msgstr "" -#: ../../language/language.md:1702 +#: ../../language/packages.md:109 msgid "" "The second rule above allows one to add new functionality to a foreign " "type by defining a new trait and implementing it. This makes MoonBit's " "trait & method system flexible while enjoying good coherence property." msgstr "" -#: ../../language/language.md:1705 +#: ../../language/packages.md:112 msgid "Visibility of traits and sealed traits" msgstr "" -#: ../../language/language.md:1706 +#: ../../language/packages.md:113 msgid "" "There are four visibility for traits, just like `struct` and `enum`: " "private, abstract, readonly and fully public. Private traits are declared" @@ -4753,12 +5580,16 @@ msgid "" "can be involked from outside, but only the current package can add new " "implementation for readonly traits. Finally, fully public traits are " "declared with `pub(open) trait`, they are open to new implementations " -"outside current package, and their methods can be freely used. Currently," -" `pub trait` defaults to `pub(open) trait`. But in the future, the " -"semantic of `pub trait` will be ported to `pub(readonly)`." +"outside current package, and their methods can be freely used." +msgstr "" + +#: ../../language/packages.md:120 +msgid "" +"Currently, `pub trait` defaults to `pub(open) trait`. But in the future, " +"the semantic of `pub trait` will be ported to `pub(readonly)`." msgstr "" -#: ../../language/language.md:1713 +#: ../../language/packages.md:123 msgid "" "Abstract and readonly traits are sealed, because only the package " "defining the trait can implement them. Implementing a sealed (abstract or" @@ -4770,22 +5601,22 @@ msgid "" " not be available outside." msgstr "" -#: ../../language/language.md:1719 +#: ../../language/packages.md:129 msgid "Here's an example of abstract trait:" msgstr "" -#: ../../language/language.md:1722 +#: ../../language/packages.md:132 msgid "" "trait Number {\n" " op_add(Self, Self) -> Self\n" " op_sub(Self, Self) -> Self\n" "}\n" "\n" -"fn add[N : Number](x : X, y: X) -> X {\n" +"fn add[N : Number](x : N, y: N) -> N {\n" " Number::op_add(x, y)\n" "}\n" "\n" -"fn sub[N : Number](x : X, y: X) -> X {\n" +"fn sub[N : Number](x : N, y: N) -> N {\n" " Number::op_sub(x, y)\n" "}\n" "\n" @@ -4796,11 +5627,11 @@ msgid "" "impl Number for Double with op_sub(x, y) { x - y }\n" msgstr "" -#: ../../language/language.md:1743 +#: ../../language/packages.md:153 msgid "From outside this package, users can only see the following:" msgstr "" -#: ../../language/language.md:1745 +#: ../../language/packages.md:155 msgid "" "trait Number\n" "\n" @@ -4811,281 +5642,227 @@ msgid "" "impl Number for Double\n" msgstr "" -#: ../../language/language.md:1755 +#: ../../language/packages.md:165 msgid "" "The author of `Number` can make use of the fact that only `Int` and " "`Double` can ever implement `Number`, because new implementations are not" " allowed outside." msgstr "" -#: ../../language/language.md:1758 -msgid "Automatically derive builtin traits" +#: ../../language/tests.md:1 +msgid "Writing Tests" msgstr "" -#: ../../language/language.md:1760 -msgid "MoonBit can automatically derive implementations for some builtin traits:" +#: ../../language/tests.md:3 +msgid "" +"Tests are important for improving quality and maintainability of a " +"program. They verify the behavior of a program and also serves as a " +"specification to avoid regressions over time." +msgstr "" + +#: ../../language/tests.md:5 +msgid "MoonBit comes with test support to make the writing easier and simpler." +msgstr "" + +#: ../../language/tests.md:7 +msgid "Test Blocks" msgstr "" -#: ../../language/language.md:1762 +#: ../../language/tests.md:9 msgid "" -"struct T {\n" -" x : Int\n" -" y : Int\n" -"} derive(Eq, Compare, Show, Default)\n" -"\n" -"test {\n" -" let t1 = T::default()\n" -" let t2 = T::{ x: 1, y: 1 }\n" -" inspect!(t1, content=\"{x: 0, y: 0}\")\n" -" inspect!(t2, content=\"{x: 1, y: 1}\")\n" -" assert_not_eq!(t1, t2)\n" -" assert_true!(t1 < t2)\n" -"}\n" +"MoonBit provides the test code block for writing inline test cases. For " +"example:" msgstr "" -#: ../../language/language.md:1768 -msgid "Trait objects" +#: ../../language/tests.md:17 +msgid "" +"A test code block is essentially a function that returns a `Unit` but may" +" throws a `String` on error, or `Unit!String` as one would see in its " +"signature at the position of return type. It is called during the " +"execution of `moon test` and outputs a test report through the build " +"system. The `assert_eq` function is from the standard library; if the " +"assertion fails, it prints an error message and terminates the test. The " +"string `\"test_name\"` is used to identify the test case and is optional." msgstr "" -#: ../../language/language.md:1770 +#: ../../language/tests.md:19 msgid "" -"MoonBit supports runtime polymorphism via trait objects. If `t` is of " -"type `T`, which implements trait `I`, one can pack the methods of `T` " -"that implements `I`, together with `t`, into a runtime object via `t as " -"I`. Trait object erases the concrete type of a value, so objects created " -"from different concrete types can be put in the same data structure and " -"handled uniformly:" +"If a test name starts with `\"panic\"`, it indicates that the expected " +"behavior of the test is to trigger a panic, and the test will only pass " +"if the panic is triggered. For example:" msgstr "" -#: ../../language/language.md:1777 +#: ../../language/tests.md:21 msgid "" -"trait Animal {\n" -" speak(Self) -> String\n" -"}\n" -"\n" -"type Duck String\n" -"\n" -"fn Duck::make(name : String) -> Duck {\n" -" Duck(name)\n" -"}\n" -"\n" -"fn speak(self : Duck) -> String {\n" -" \"\\{self._}: quack!\"\n" -"}\n" -"\n" -"type Fox String\n" -"\n" -"fn Fox::make(name : String) -> Fox {\n" -" Fox(name)\n" -"}\n" -"\n" -"fn Fox::speak(_self : Fox) -> String {\n" -" \"What does the fox say?\"\n" -"}\n" +"test \"panic_test\" {\n" +" let _ : Int = Option::None.unwrap()\n" "\n" -"test {\n" -" let duck1 = Duck::make(\"duck1\")\n" -" let duck2 = Duck::make(\"duck2\")\n" -" let fox1 = Fox::make(\"fox1\")\n" -" let animals : Array[Animal] = [\n" -" duck1 as Animal,\n" -" duck2 as Animal,\n" -" fox1 as Animal,\n" -" ]\n" -" inspect!(\n" -" animals.map(fn(animal) { animal.speak() }),\n" -" content=\n" -" #|[\"duck1: quack!\", \"duck2: quack!\", \"What does the fox " -"say?\"]\n" -" ,\n" -" )\n" "}\n" msgstr "" -#: ../../language/language.md:1783 -msgid "" -"Not all traits can be used to create objects. \"object-safe\" traits' " -"methods must satisfy the following conditions:" +#: ../../language/tests.md:27 +msgid "Snapshot Tests" msgstr "" -#: ../../language/language.md:1786 -msgid "`Self` must be the first parameter of a method" +#: ../../language/tests.md:29 +msgid "" +"Writing tests can be tedious when specifying the expected values. Thus, " +"MoonBit provides three kinds of snapshot tests. All of which can be " +"inserted or updated automatically using `moon test --update`." msgstr "" -#: ../../language/language.md:1787 -msgid "" -"There must be only one occurrence of `Self` in the type of the method " -"(i.e. the first parameter)" +#: ../../language/tests.md:32 +msgid "Snapshotting `Show`" msgstr "" -#: ../../language/language.md:1789 +#: ../../language/tests.md:34 msgid "" -"Users can define new methods for trait objects, just like defining new " -"methods for structs and enums:" +"We can use `inspect!(x, content=\"x\")` to inspect anything that " +"implements `Show` trait. As we mentioned before, `Show` is a builtin " +"trait that can be derived, providing `to_string` that will print the " +"content of the data structures. The labelled argument `content` can be " +"omitted as `moon test --update` will insert it for you:" msgstr "" -#: ../../language/language.md:1791 +#: ../../language/tests.md:38 msgid "" -"trait Logger {\n" -" write_string(Self, String) -> Unit\n" -"}\n" -"\n" -"trait CanLog {\n" -" log(Self, Logger) -> Unit\n" -"}\n" +"struct X { x : Int } derive(Show)\n" "\n" -"fn Logger::write_object[Obj : CanLog](self : Logger, obj : Obj) -> Unit {" -"\n" -" obj.log(self)\n" -"}\n" -"\n" -"// use the new method to simplify code\n" -"impl[A : CanLog, B : CanLog] CanLog for (A, B) with log(self, logger) {\n" -" let (a, b) = self\n" -" logger\n" -" ..write_string(\"(\")\n" -" ..write_object(a)\n" -" ..write_string(\", \")\n" -" ..write_object(b)\n" -" .write_string(\")\")\n" +"test \"show snapshot test\" {\n" +" inspect!({x: 10}, content=\"{x: 10}\")\n" "}\n" msgstr "" -#: ../../language/language.md:1797 -msgid "Test Blocks" -msgstr "" - -#: ../../language/language.md:1799 -msgid "MoonBit provides the test code block for writing test cases. For example:" +#: ../../language/tests.md:44 +msgid "Snapshotting `JSON`" msgstr "" -#: ../../language/language.md:1801 +#: ../../language/tests.md:46 msgid "" -"test \"test_name\" {\n" -" assert_eq!(1 + 1, 2)\n" -" assert_eq!(2 + 2, 4)\n" -"}\n" +"The problem with the derived `Show` trait is that it does not perform " +"pretty printing, resulting in extremely long output." msgstr "" -#: ../../language/language.md:1807 +#: ../../language/tests.md:48 msgid "" -"A test code block is essentially a function that returns a `Unit` but may" -" throws a `String` on error, or `Unit!String` as one would see in its " -"signature at the position of return type. It is called during the " -"execution of `moon test` and outputs a test report through the build " -"system. The `assert_eq` function is from the standard library; if the " -"assertion fails, it prints an error message and terminates the test. The " -"string `\"test_name\"` is used to identify the test case and is optional." -" If it starts with `\"panic\"`, it indicates that the expected behavior " -"of the test is to trigger a panic, and the test will only pass if the " -"panic is triggered. For example:" +"The solution is to use `@json.inspect!(x, content=x)`. The benefit is " +"that the resulting content is a JSON structure, which can be more " +"readable after being formatted." msgstr "" -#: ../../language/language.md:1809 +#: ../../language/tests.md:50 msgid "" -"test \"panic_test\" {\n" -" let _ : Int = Option::None.unwrap()\n" +"enum Rec {\n" +" End\n" +" Really_long_name_that_is_difficult_to_read(Rec)\n" +"} derive(Show, ToJson)\n" +"\n" +"test \"json snapshot test\" {\n" +" let r = Really_long_name_that_is_difficult_to_read(\n" +" Really_long_name_that_is_difficult_to_read(\n" +" Really_long_name_that_is_difficult_to_read(End),\n" +" ),\n" +" )\n" +" inspect!(\n" +" r,\n" +" " +"content=\"Really_long_name_that_is_difficult_to_read(Really_long_name_that_is_difficult_to_read(Really_long_name_that_is_difficult_to_read(End)))\"," "\n" +" )\n" +" @json.inspect!(\n" +" r,\n" +" content={\n" +" \"$tag\": \"Really_long_name_that_is_difficult_to_read\",\n" +" \"0\": {\n" +" \"$tag\": \"Really_long_name_that_is_difficult_to_read\",\n" +" \"0\": {\n" +" \"$tag\": \"Really_long_name_that_is_difficult_to_read\",\n" +" \"0\": { \"$tag\": \"End\" },\n" +" },\n" +" },\n" +" },\n" +" )\n" "}\n" msgstr "" -#: ../../language/language.md:1815 -msgid "Doc Comments" -msgstr "" - -#: ../../language/language.md:1817 +#: ../../language/tests.md:56 msgid "" -"Doc comments are comments prefix with `///` in each line in the leading " -"of toplevel structure like `fn`,`let`,`enum`,`struct`,`type`. The doc " -"comments contains a markdown text and several pragmas." +"One can also implement a custom `ToJson` to keep only the essential " +"information." msgstr "" -#: ../../language/language.md:1819 -msgid "" -"/// Return a new array with reversed elements.\n" -"///\n" -"/// # Example\n" -"///\n" -"/// ```\n" -"/// reverse([1,2,3,4]) |> println()\n" -"/// ```\n" -"fn reverse[T](xs : Array[T]) -> Array[T] {\n" -" ...\n" -"}\n" +#: ../../language/tests.md:58 +msgid "Snapshotting Anything" msgstr "" -#: ../../language/language.md:1825 -msgid "Pragmas" +#: ../../language/tests.md:60 +msgid "" +"Still, sometimes we want to not only record one data structure but the " +"output of a whole process." msgstr "" -#: ../../language/language.md:1827 +#: ../../language/tests.md:62 msgid "" -"Pragmas are annotations inside doc comments. They all take the form `/// " -"@word ...`. The _word_ indicates the type of pragma and is followed " -"optionally by several _word_ or string literals. Pragmas do not normally " -"affect the meaning of programs. Unrecognized pragmas will be reported as " -"warnings." +"A full snapshot test can be used to record anything using " +"`@test.T::write` and `@test.T::writeln`:" msgstr "" -#: ../../language/language.md:1829 -msgid "Alert Pragmas" +#: ../../language/tests.md:64 +msgid "" +"test \"record anything\" (t : @test.T) {\n" +" t.write(\"Hello, world!\")\n" +" t.writeln(\" And hello, MoonBit!\")\n" +" t.snapshot!(filename=\"record_anything.txt\")\n" +"}\n" msgstr "" -#: ../../language/language.md:1831 +#: ../../language/tests.md:70 msgid "" -"Alert pragmas in doc comments of functions will be reported when those " -"functions are referenced. This mechanism is a generalized way to mark " -"functions as `deprecated` or `unsafe`." +"This will create a file under `__snapshot__` of that package with the " +"given filename:" msgstr "" -#: ../../language/language.md:1833 -msgid "It takes the form `@alert category \"alert message...\"`." +#: ../../language/tests.md:72 +msgid "Hello, world! And hello, MoonBit!\n" msgstr "" -#: ../../language/language.md:1835 +#: ../../language/tests.md:75 msgid "" -"The category can be an arbitrary identifier. It allows configuration to " -"decide which alerts are enabled or turned into errors." +"This can also be used for applications to test the generated output, " +"whether it were creating an image, a video or some custom data." msgstr "" -#: ../../language/language.md:1838 -msgid "" -"/// @alert deprecated \"Use foo2 instead\"\n" -"pub fn foo() -> Unit {\n" -" ...\n" -"}\n" -"\n" -"/// @alert unsafe \"Div will cause an error when y is zero\"\n" -"pub fn div(x : Int, y : Int) -> Int {\n" -" ...\n" -"}\n" -"\n" -"test {\n" -" // Warning (Alert deprecated): Use foo2 instead\n" -" foo()\n" -" // Warning (Alert unsafe): Div will cause an error when y is zero\n" -" div(1, 2) |> ignore\n" -"}\n" +#: ../../language/tests.md:77 +msgid "BlackBox Tests and WhiteBox Tests" msgstr "" -#: ../../language/language.md:1857 -msgid "Special Syntax" +#: ../../language/tests.md:79 +msgid "" +"When developing libraries, it is important to verify if the user can use " +"it correctly. For example, one may forget to make a type or a function " +"public. That's why MoonBit provides BlackBox tests, allowing developers " +"to have a grasp of how others are feeling." msgstr "" -#: ../../language/language.md:1859 -msgid "TODO syntax" +#: ../../language/tests.md:81 +msgid "" +"A test that has access to all the members in a package is called a " +"WhiteBox tests as we can see everything. Such tests can be defined inline" +" or defined in a file whose name ends with `_wbtest.mbt`." msgstr "" -#: ../../language/language.md:1861 +#: ../../language/tests.md:83 msgid "" -"The `todo` syntax (`...`) is a special construct used to mark sections of" -" code that are not yet implemented or are placeholders for future " -"functionality. For example:" +"A test that has access only to the public members in a package is called " +"a BlackBox tests. Such tests need to be defined in a file whose name ends" +" with `_test.mbt`." msgstr "" -#: ../../language/language.md:1863 +#: ../../language/tests.md:85 msgid "" -"fn todo_in_func() -> Int {\n" -" ...\n" -"}\n" +"The WhiteBox test files (`_wbtest.mbt`) imports the packages defined in " +"the `import` and `wbtest-import` sections of the package configuration " +"(`moon.pkg.json`). The BlackBox test files (`_test.mbt`) imports the " +"current package and the packages defined in the `import` and `test-" +"import` sections of the package configuration (`moon.pkg.json`)." msgstr "" diff --git a/next/locales/zh_CN/LC_MESSAGES/toolchain.po b/next/locales/zh_CN/LC_MESSAGES/toolchain.po index 2aaf4b8d..46c34a25 100644 --- a/next/locales/zh_CN/LC_MESSAGES/toolchain.po +++ b/next/locales/zh_CN/LC_MESSAGES/toolchain.po @@ -9,7 +9,7 @@ msgid "" msgstr "" "Project-Id-Version: MoonBit Document \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-11-28 16:03+0800\n" +"POT-Creation-Date: 2024-12-18 11:20+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: zh_CN\n" @@ -174,7 +174,7 @@ msgstr "" msgid "**Usage:** `moon `" msgstr "" -#: ../../toolchain/moon/commands.md:38 ../../toolchain/moon/commands.md:376 +#: ../../toolchain/moon/commands.md:38 ../../toolchain/moon/commands.md:388 msgid "**Subcommands:**" msgstr "" @@ -288,10 +288,10 @@ msgstr "" msgid "**Usage:** `moon new [OPTIONS] [PACKAGE_NAME]`" msgstr "" -#: ../../toolchain/moon/commands.md:72 ../../toolchain/moon/commands.md:122 -#: ../../toolchain/moon/commands.md:156 ../../toolchain/moon/commands.md:234 -#: ../../toolchain/moon/commands.md:287 ../../toolchain/moon/commands.md:299 -#: ../../toolchain/moon/commands.md:389 +#: ../../toolchain/moon/commands.md:72 ../../toolchain/moon/commands.md:124 +#: ../../toolchain/moon/commands.md:160 ../../toolchain/moon/commands.md:242 +#: ../../toolchain/moon/commands.md:295 ../../toolchain/moon/commands.md:311 +#: ../../toolchain/moon/commands.md:401 msgid "**Arguments:**" msgstr "" @@ -300,13 +300,13 @@ msgid "`` — The name of the package" msgstr "" #: ../../toolchain/moon/commands.md:76 ../../toolchain/moon/commands.md:95 -#: ../../toolchain/moon/commands.md:126 ../../toolchain/moon/commands.md:161 -#: ../../toolchain/moon/commands.md:188 ../../toolchain/moon/commands.md:238 -#: ../../toolchain/moon/commands.md:255 ../../toolchain/moon/commands.md:274 -#: ../../toolchain/moon/commands.md:343 ../../toolchain/moon/commands.md:355 -#: ../../toolchain/moon/commands.md:393 ../../toolchain/moon/commands.md:413 -#: ../../toolchain/moon/commands.md:430 ../../toolchain/moon/commands.md:575 -#: ../../toolchain/moon/commands.md:592 +#: ../../toolchain/moon/commands.md:128 ../../toolchain/moon/commands.md:165 +#: ../../toolchain/moon/commands.md:194 ../../toolchain/moon/commands.md:246 +#: ../../toolchain/moon/commands.md:263 ../../toolchain/moon/commands.md:282 +#: ../../toolchain/moon/commands.md:299 ../../toolchain/moon/commands.md:355 +#: ../../toolchain/moon/commands.md:367 ../../toolchain/moon/commands.md:405 +#: ../../toolchain/moon/commands.md:425 ../../toolchain/moon/commands.md:442 +#: ../../toolchain/moon/commands.md:587 ../../toolchain/moon/commands.md:604 msgid "**Options:**" msgstr "" @@ -350,533 +350,547 @@ msgstr "" msgid "**Usage:** `moon build [OPTIONS]`" msgstr "" -#: ../../toolchain/moon/commands.md:97 ../../toolchain/moon/commands.md:128 -#: ../../toolchain/moon/commands.md:163 ../../toolchain/moon/commands.md:190 +#: ../../toolchain/moon/commands.md:97 ../../toolchain/moon/commands.md:130 +#: ../../toolchain/moon/commands.md:167 ../../toolchain/moon/commands.md:196 msgid "`--std` — Enable the standard library (default)" msgstr "" -#: ../../toolchain/moon/commands.md:98 ../../toolchain/moon/commands.md:129 -#: ../../toolchain/moon/commands.md:164 ../../toolchain/moon/commands.md:191 +#: ../../toolchain/moon/commands.md:98 ../../toolchain/moon/commands.md:131 +#: ../../toolchain/moon/commands.md:168 ../../toolchain/moon/commands.md:197 msgid "`--nostd` — Disable the standard library" msgstr "" -#: ../../toolchain/moon/commands.md:99 ../../toolchain/moon/commands.md:130 -#: ../../toolchain/moon/commands.md:165 ../../toolchain/moon/commands.md:192 +#: ../../toolchain/moon/commands.md:99 ../../toolchain/moon/commands.md:132 +#: ../../toolchain/moon/commands.md:169 ../../toolchain/moon/commands.md:198 msgid "`-g`, `--debug` — Emit debug information" msgstr "" -#: ../../toolchain/moon/commands.md:100 ../../toolchain/moon/commands.md:131 -#: ../../toolchain/moon/commands.md:166 ../../toolchain/moon/commands.md:193 +#: ../../toolchain/moon/commands.md:100 ../../toolchain/moon/commands.md:133 +#: ../../toolchain/moon/commands.md:170 ../../toolchain/moon/commands.md:199 msgid "`--release` — Compile in release mode" msgstr "" -#: ../../toolchain/moon/commands.md:101 ../../toolchain/moon/commands.md:132 -#: ../../toolchain/moon/commands.md:167 ../../toolchain/moon/commands.md:194 +#: ../../toolchain/moon/commands.md:101 ../../toolchain/moon/commands.md:134 +#: ../../toolchain/moon/commands.md:171 ../../toolchain/moon/commands.md:200 msgid "`--target ` — Select output target" msgstr "" -#: ../../toolchain/moon/commands.md:103 ../../toolchain/moon/commands.md:134 -#: ../../toolchain/moon/commands.md:169 ../../toolchain/moon/commands.md:196 +#: ../../toolchain/moon/commands.md:103 ../../toolchain/moon/commands.md:136 +#: ../../toolchain/moon/commands.md:173 ../../toolchain/moon/commands.md:202 msgid "Possible values: `wasm`, `wasm-gc`, `js`, `native`, `all`" msgstr "" -#: ../../toolchain/moon/commands.md:105 ../../toolchain/moon/commands.md:136 -#: ../../toolchain/moon/commands.md:171 ../../toolchain/moon/commands.md:198 +#: ../../toolchain/moon/commands.md:105 ../../toolchain/moon/commands.md:138 +#: ../../toolchain/moon/commands.md:175 ../../toolchain/moon/commands.md:204 msgid "`--serial` — Handle the selected targets sequentially" msgstr "" -#: ../../toolchain/moon/commands.md:106 ../../toolchain/moon/commands.md:137 -#: ../../toolchain/moon/commands.md:172 ../../toolchain/moon/commands.md:199 +#: ../../toolchain/moon/commands.md:106 ../../toolchain/moon/commands.md:139 +#: ../../toolchain/moon/commands.md:176 ../../toolchain/moon/commands.md:205 msgid "`--enable-coverage` — Enable coverage instrumentation" msgstr "" -#: ../../toolchain/moon/commands.md:107 ../../toolchain/moon/commands.md:138 -#: ../../toolchain/moon/commands.md:173 ../../toolchain/moon/commands.md:200 -#: ../../toolchain/moon/commands.md:241 +#: ../../toolchain/moon/commands.md:107 ../../toolchain/moon/commands.md:140 +#: ../../toolchain/moon/commands.md:177 ../../toolchain/moon/commands.md:206 +#: ../../toolchain/moon/commands.md:249 msgid "`--sort-input` — Sort input files" msgstr "" -#: ../../toolchain/moon/commands.md:108 ../../toolchain/moon/commands.md:139 -#: ../../toolchain/moon/commands.md:174 ../../toolchain/moon/commands.md:201 +#: ../../toolchain/moon/commands.md:108 ../../toolchain/moon/commands.md:141 +#: ../../toolchain/moon/commands.md:178 ../../toolchain/moon/commands.md:207 msgid "`--output-wat` — Output WAT instead of WASM" msgstr "" -#: ../../toolchain/moon/commands.md:109 ../../toolchain/moon/commands.md:140 -#: ../../toolchain/moon/commands.md:175 ../../toolchain/moon/commands.md:202 +#: ../../toolchain/moon/commands.md:109 ../../toolchain/moon/commands.md:142 +#: ../../toolchain/moon/commands.md:179 ../../toolchain/moon/commands.md:208 msgid "`-d`, `--deny-warn` — Treat all warnings as errors" msgstr "" -#: ../../toolchain/moon/commands.md:110 ../../toolchain/moon/commands.md:141 -#: ../../toolchain/moon/commands.md:176 ../../toolchain/moon/commands.md:203 +#: ../../toolchain/moon/commands.md:110 ../../toolchain/moon/commands.md:143 +#: ../../toolchain/moon/commands.md:180 ../../toolchain/moon/commands.md:209 msgid "" "`--no-render` — Don't render diagnostics from moonc (don't pass '-error-" "format json' to moonc)" msgstr "" -#: ../../toolchain/moon/commands.md:111 ../../toolchain/moon/commands.md:143 -#: ../../toolchain/moon/commands.md:177 ../../toolchain/moon/commands.md:211 -#: ../../toolchain/moon/commands.md:264 ../../toolchain/moon/commands.md:276 -#: ../../toolchain/moon/commands.md:345 ../../toolchain/moon/commands.md:357 +#: ../../toolchain/moon/commands.md:111 ../../toolchain/moon/commands.md:144 +#: ../../toolchain/moon/commands.md:181 ../../toolchain/moon/commands.md:210 +msgid "`--warn-list ` — Warn list config" +msgstr "" + +#: ../../toolchain/moon/commands.md:112 ../../toolchain/moon/commands.md:145 +#: ../../toolchain/moon/commands.md:182 ../../toolchain/moon/commands.md:211 +msgid "`--alert-list ` — Alert list config" +msgstr "" + +#: ../../toolchain/moon/commands.md:113 ../../toolchain/moon/commands.md:147 +#: ../../toolchain/moon/commands.md:183 ../../toolchain/moon/commands.md:219 +#: ../../toolchain/moon/commands.md:272 ../../toolchain/moon/commands.md:284 +#: ../../toolchain/moon/commands.md:357 ../../toolchain/moon/commands.md:369 msgid "" "`--frozen` — Do not sync dependencies, assuming local dependencies are " "up-to-date" msgstr "" -#: ../../toolchain/moon/commands.md:112 +#: ../../toolchain/moon/commands.md:114 msgid "" "`-w`, `--watch` — Monitor the file system and automatically build " "artifacts" msgstr "" -#: ../../toolchain/moon/commands.md:116 +#: ../../toolchain/moon/commands.md:118 msgid "`moon check`" msgstr "" -#: ../../toolchain/moon/commands.md:118 +#: ../../toolchain/moon/commands.md:120 msgid "Check the current package, but don't build object files" msgstr "" -#: ../../toolchain/moon/commands.md:120 +#: ../../toolchain/moon/commands.md:122 msgid "**Usage:** `moon check [OPTIONS] [PACKAGE_PATH]`" msgstr "" -#: ../../toolchain/moon/commands.md:124 +#: ../../toolchain/moon/commands.md:126 msgid "`` — The package(and it's deps) to check" msgstr "" -#: ../../toolchain/moon/commands.md:142 +#: ../../toolchain/moon/commands.md:146 msgid "`--output-json` — Output in json format" msgstr "" -#: ../../toolchain/moon/commands.md:144 +#: ../../toolchain/moon/commands.md:148 msgid "`-w`, `--watch` — Monitor the file system and automatically check files" msgstr "" -#: ../../toolchain/moon/commands.md:145 +#: ../../toolchain/moon/commands.md:149 msgid "" "`--patch-file ` — The patch file to check, Only valid when " "checking specified package" msgstr "" -#: ../../toolchain/moon/commands.md:146 +#: ../../toolchain/moon/commands.md:150 msgid "" "`--no-mi` — Whether to skip the mi generation, Only valid when checking " "specified package" msgstr "" -#: ../../toolchain/moon/commands.md:150 +#: ../../toolchain/moon/commands.md:154 msgid "`moon run`" msgstr "" -#: ../../toolchain/moon/commands.md:152 +#: ../../toolchain/moon/commands.md:156 msgid "Run a main package" msgstr "" -#: ../../toolchain/moon/commands.md:154 +#: ../../toolchain/moon/commands.md:158 msgid "**Usage:** `moon run [OPTIONS] [ARGS]...`" msgstr "" -#: ../../toolchain/moon/commands.md:158 +#: ../../toolchain/moon/commands.md:162 msgid "`` — The package or .mbt file to run" msgstr "" -#: ../../toolchain/moon/commands.md:159 +#: ../../toolchain/moon/commands.md:163 msgid "`` — The arguments provided to the program to be run" msgstr "" -#: ../../toolchain/moon/commands.md:178 +#: ../../toolchain/moon/commands.md:184 msgid "`--build-only` — Only build, do not run the code" msgstr "" -#: ../../toolchain/moon/commands.md:182 +#: ../../toolchain/moon/commands.md:188 msgid "`moon test`" msgstr "" -#: ../../toolchain/moon/commands.md:184 +#: ../../toolchain/moon/commands.md:190 msgid "Test the current package" msgstr "" -#: ../../toolchain/moon/commands.md:186 +#: ../../toolchain/moon/commands.md:192 msgid "**Usage:** `moon test [OPTIONS]`" msgstr "" -#: ../../toolchain/moon/commands.md:204 +#: ../../toolchain/moon/commands.md:212 msgid "`-p`, `--package ` — Run test in the specified package" msgstr "" -#: ../../toolchain/moon/commands.md:205 +#: ../../toolchain/moon/commands.md:213 msgid "" "`-f`, `--file ` — Run test in the specified file. Only valid when " "`--package` is also specified" msgstr "" -#: ../../toolchain/moon/commands.md:206 +#: ../../toolchain/moon/commands.md:214 msgid "" "`-i`, `--index ` — Run only the index-th test in the file. Only " "valid when `--file` is also specified" msgstr "" -#: ../../toolchain/moon/commands.md:207 +#: ../../toolchain/moon/commands.md:215 msgid "`-u`, `--update` — Update the test snapshot" msgstr "" -#: ../../toolchain/moon/commands.md:208 +#: ../../toolchain/moon/commands.md:216 msgid "" "`-l`, `--limit ` — Limit of expect test update passes to run, in " "order to avoid infinite loops" msgstr "" -#: ../../toolchain/moon/commands.md:210 +#: ../../toolchain/moon/commands.md:218 msgid "Default value: `256`" msgstr "" -#: ../../toolchain/moon/commands.md:212 +#: ../../toolchain/moon/commands.md:220 msgid "`--build-only` — Only build, do not run the tests" msgstr "" -#: ../../toolchain/moon/commands.md:213 +#: ../../toolchain/moon/commands.md:221 msgid "`--no-parallelize` — Run the tests in a target backend sequentially" msgstr "" -#: ../../toolchain/moon/commands.md:214 +#: ../../toolchain/moon/commands.md:222 msgid "`--test-failure-json` — Print failure message in JSON format" msgstr "" -#: ../../toolchain/moon/commands.md:215 +#: ../../toolchain/moon/commands.md:223 msgid "`--patch-file ` — Path to the patch file" msgstr "" -#: ../../toolchain/moon/commands.md:216 +#: ../../toolchain/moon/commands.md:224 msgid "`--doc` — Run doc test" msgstr "" -#: ../../toolchain/moon/commands.md:220 +#: ../../toolchain/moon/commands.md:228 msgid "`moon clean`" msgstr "" -#: ../../toolchain/moon/commands.md:222 +#: ../../toolchain/moon/commands.md:230 msgid "Remove the target directory" msgstr "" -#: ../../toolchain/moon/commands.md:224 +#: ../../toolchain/moon/commands.md:232 msgid "**Usage:** `moon clean`" msgstr "" -#: ../../toolchain/moon/commands.md:228 +#: ../../toolchain/moon/commands.md:236 msgid "`moon fmt`" msgstr "" -#: ../../toolchain/moon/commands.md:230 +#: ../../toolchain/moon/commands.md:238 msgid "Format source code" msgstr "" -#: ../../toolchain/moon/commands.md:232 +#: ../../toolchain/moon/commands.md:240 msgid "**Usage:** `moon fmt [OPTIONS] [ARGS]...`" msgstr "" -#: ../../toolchain/moon/commands.md:236 +#: ../../toolchain/moon/commands.md:244 msgid "``" msgstr "" -#: ../../toolchain/moon/commands.md:240 +#: ../../toolchain/moon/commands.md:248 msgid "`--check` — Check only and don't change the source code" msgstr "" -#: ../../toolchain/moon/commands.md:242 +#: ../../toolchain/moon/commands.md:250 msgid "`--block-style ` — Add separator between each segments" msgstr "" -#: ../../toolchain/moon/commands.md:244 +#: ../../toolchain/moon/commands.md:252 msgid "Possible values: `false`, `true`" msgstr "" -#: ../../toolchain/moon/commands.md:249 +#: ../../toolchain/moon/commands.md:257 msgid "`moon doc`" msgstr "" -#: ../../toolchain/moon/commands.md:251 +#: ../../toolchain/moon/commands.md:259 msgid "Generate documentation" msgstr "" -#: ../../toolchain/moon/commands.md:253 +#: ../../toolchain/moon/commands.md:261 msgid "**Usage:** `moon doc [OPTIONS]`" msgstr "" -#: ../../toolchain/moon/commands.md:257 +#: ../../toolchain/moon/commands.md:265 msgid "`--serve` — Start a web server to serve the documentation" msgstr "" -#: ../../toolchain/moon/commands.md:258 +#: ../../toolchain/moon/commands.md:266 msgid "`-b`, `--bind ` — The address of the server" msgstr "" -#: ../../toolchain/moon/commands.md:260 +#: ../../toolchain/moon/commands.md:268 msgid "Default value: `127.0.0.1`" msgstr "" -#: ../../toolchain/moon/commands.md:261 +#: ../../toolchain/moon/commands.md:269 msgid "`-p`, `--port ` — The port of the server" msgstr "" -#: ../../toolchain/moon/commands.md:263 +#: ../../toolchain/moon/commands.md:271 msgid "Default value: `3000`" msgstr "" -#: ../../toolchain/moon/commands.md:268 +#: ../../toolchain/moon/commands.md:276 msgid "`moon info`" msgstr "" -#: ../../toolchain/moon/commands.md:270 +#: ../../toolchain/moon/commands.md:278 msgid "Generate public interface (`.mbti`) files for all packages in the module" msgstr "" -#: ../../toolchain/moon/commands.md:272 +#: ../../toolchain/moon/commands.md:280 msgid "**Usage:** `moon info [OPTIONS]`" msgstr "" -#: ../../toolchain/moon/commands.md:277 +#: ../../toolchain/moon/commands.md:285 msgid "`--no-alias` — Do not use alias to shorten package names in the output" msgstr "" -#: ../../toolchain/moon/commands.md:281 +#: ../../toolchain/moon/commands.md:289 msgid "`moon add`" msgstr "" -#: ../../toolchain/moon/commands.md:283 +#: ../../toolchain/moon/commands.md:291 msgid "Add a dependency" msgstr "" -#: ../../toolchain/moon/commands.md:285 -msgid "**Usage:** `moon add `" +#: ../../toolchain/moon/commands.md:293 +msgid "**Usage:** `moon add [OPTIONS] `" msgstr "" -#: ../../toolchain/moon/commands.md:289 +#: ../../toolchain/moon/commands.md:297 msgid "`` — The package path to add" msgstr "" -#: ../../toolchain/moon/commands.md:293 +#: ../../toolchain/moon/commands.md:301 +msgid "`--bin` — Whether to add the dependency as a binary" +msgstr "" + +#: ../../toolchain/moon/commands.md:305 msgid "`moon remove`" msgstr "" -#: ../../toolchain/moon/commands.md:295 +#: ../../toolchain/moon/commands.md:307 msgid "Remove a dependency" msgstr "" -#: ../../toolchain/moon/commands.md:297 +#: ../../toolchain/moon/commands.md:309 msgid "**Usage:** `moon remove `" msgstr "" -#: ../../toolchain/moon/commands.md:301 +#: ../../toolchain/moon/commands.md:313 msgid "`` — The package path to remove" msgstr "" -#: ../../toolchain/moon/commands.md:305 +#: ../../toolchain/moon/commands.md:317 msgid "`moon install`" msgstr "" -#: ../../toolchain/moon/commands.md:307 +#: ../../toolchain/moon/commands.md:319 msgid "Install dependencies" msgstr "" -#: ../../toolchain/moon/commands.md:309 +#: ../../toolchain/moon/commands.md:321 msgid "**Usage:** `moon install`" msgstr "" -#: ../../toolchain/moon/commands.md:313 +#: ../../toolchain/moon/commands.md:325 msgid "`moon tree`" msgstr "" -#: ../../toolchain/moon/commands.md:315 +#: ../../toolchain/moon/commands.md:327 msgid "Display the dependency tree" msgstr "" -#: ../../toolchain/moon/commands.md:317 +#: ../../toolchain/moon/commands.md:329 msgid "**Usage:** `moon tree`" msgstr "" -#: ../../toolchain/moon/commands.md:321 +#: ../../toolchain/moon/commands.md:333 msgid "`moon login`" msgstr "" -#: ../../toolchain/moon/commands.md:323 +#: ../../toolchain/moon/commands.md:335 msgid "Log in to your account" msgstr "" -#: ../../toolchain/moon/commands.md:325 +#: ../../toolchain/moon/commands.md:337 msgid "**Usage:** `moon login`" msgstr "" -#: ../../toolchain/moon/commands.md:329 +#: ../../toolchain/moon/commands.md:341 msgid "`moon register`" msgstr "" -#: ../../toolchain/moon/commands.md:331 +#: ../../toolchain/moon/commands.md:343 msgid "Register an account at mooncakes.io" msgstr "" -#: ../../toolchain/moon/commands.md:333 +#: ../../toolchain/moon/commands.md:345 msgid "**Usage:** `moon register`" msgstr "" -#: ../../toolchain/moon/commands.md:337 +#: ../../toolchain/moon/commands.md:349 msgid "`moon publish`" msgstr "" -#: ../../toolchain/moon/commands.md:339 +#: ../../toolchain/moon/commands.md:351 msgid "Publish the current module" msgstr "" -#: ../../toolchain/moon/commands.md:341 +#: ../../toolchain/moon/commands.md:353 msgid "**Usage:** `moon publish [OPTIONS]`" msgstr "" -#: ../../toolchain/moon/commands.md:349 +#: ../../toolchain/moon/commands.md:361 msgid "`moon package`" msgstr "" -#: ../../toolchain/moon/commands.md:351 +#: ../../toolchain/moon/commands.md:363 msgid "Package the current module" msgstr "" -#: ../../toolchain/moon/commands.md:353 +#: ../../toolchain/moon/commands.md:365 msgid "**Usage:** `moon package [OPTIONS]`" msgstr "" -#: ../../toolchain/moon/commands.md:358 +#: ../../toolchain/moon/commands.md:370 msgid "`--list`" msgstr "" -#: ../../toolchain/moon/commands.md:362 +#: ../../toolchain/moon/commands.md:374 msgid "`moon update`" msgstr "" -#: ../../toolchain/moon/commands.md:364 +#: ../../toolchain/moon/commands.md:376 msgid "Update the package registry index" msgstr "" -#: ../../toolchain/moon/commands.md:366 +#: ../../toolchain/moon/commands.md:378 msgid "**Usage:** `moon update`" msgstr "" -#: ../../toolchain/moon/commands.md:370 +#: ../../toolchain/moon/commands.md:382 msgid "`moon coverage`" msgstr "" -#: ../../toolchain/moon/commands.md:372 +#: ../../toolchain/moon/commands.md:384 msgid "Code coverage utilities" msgstr "" -#: ../../toolchain/moon/commands.md:374 +#: ../../toolchain/moon/commands.md:386 msgid "**Usage:** `moon coverage `" msgstr "" -#: ../../toolchain/moon/commands.md:378 +#: ../../toolchain/moon/commands.md:390 msgid "`report` — Generate code coverage report" msgstr "" -#: ../../toolchain/moon/commands.md:379 +#: ../../toolchain/moon/commands.md:391 msgid "`clean` — Clean up coverage artifacts" msgstr "" -#: ../../toolchain/moon/commands.md:383 +#: ../../toolchain/moon/commands.md:395 msgid "`moon coverage report`" msgstr "" -#: ../../toolchain/moon/commands.md:385 +#: ../../toolchain/moon/commands.md:397 msgid "Generate code coverage report" msgstr "" -#: ../../toolchain/moon/commands.md:387 +#: ../../toolchain/moon/commands.md:399 msgid "**Usage:** `moon coverage report [args]... [COMMAND]`" msgstr "" -#: ../../toolchain/moon/commands.md:391 +#: ../../toolchain/moon/commands.md:403 msgid "`` — Arguments to pass to the coverage utility" msgstr "" -#: ../../toolchain/moon/commands.md:395 +#: ../../toolchain/moon/commands.md:407 msgid "`-h`, `--help` — Show help for the coverage utility" msgstr "" -#: ../../toolchain/moon/commands.md:399 +#: ../../toolchain/moon/commands.md:411 msgid "`moon coverage clean`" msgstr "" -#: ../../toolchain/moon/commands.md:401 +#: ../../toolchain/moon/commands.md:413 msgid "Clean up coverage artifacts" msgstr "" -#: ../../toolchain/moon/commands.md:403 +#: ../../toolchain/moon/commands.md:415 msgid "**Usage:** `moon coverage clean`" msgstr "" -#: ../../toolchain/moon/commands.md:407 +#: ../../toolchain/moon/commands.md:419 msgid "`moon generate-build-matrix`" msgstr "" -#: ../../toolchain/moon/commands.md:409 +#: ../../toolchain/moon/commands.md:421 msgid "Generate build matrix for benchmarking (legacy feature)" msgstr "" -#: ../../toolchain/moon/commands.md:411 +#: ../../toolchain/moon/commands.md:423 msgid "**Usage:** `moon generate-build-matrix [OPTIONS] --output-dir `" msgstr "" -#: ../../toolchain/moon/commands.md:415 +#: ../../toolchain/moon/commands.md:427 msgid "" "`-n ` — Set all of `drow`, `dcol`, `mrow`, `mcol` to the same " "value" msgstr "" -#: ../../toolchain/moon/commands.md:416 +#: ../../toolchain/moon/commands.md:428 msgid "`--drow ` — Number of directory rows" msgstr "" -#: ../../toolchain/moon/commands.md:417 +#: ../../toolchain/moon/commands.md:429 msgid "`--dcol ` — Number of directory columns" msgstr "" -#: ../../toolchain/moon/commands.md:418 +#: ../../toolchain/moon/commands.md:430 msgid "`--mrow ` — Number of module rows" msgstr "" -#: ../../toolchain/moon/commands.md:419 +#: ../../toolchain/moon/commands.md:431 msgid "`--mcol ` — Number of module columns" msgstr "" -#: ../../toolchain/moon/commands.md:420 +#: ../../toolchain/moon/commands.md:432 msgid "`-o`, `--output-dir ` — The output directory" msgstr "" -#: ../../toolchain/moon/commands.md:424 +#: ../../toolchain/moon/commands.md:436 msgid "`moon upgrade`" msgstr "" -#: ../../toolchain/moon/commands.md:426 +#: ../../toolchain/moon/commands.md:438 msgid "Upgrade toolchains" msgstr "" -#: ../../toolchain/moon/commands.md:428 +#: ../../toolchain/moon/commands.md:440 msgid "**Usage:** `moon upgrade [OPTIONS]`" msgstr "" -#: ../../toolchain/moon/commands.md:432 +#: ../../toolchain/moon/commands.md:444 msgid "`-f`, `--force` — Force upgrade" msgstr "" -#: ../../toolchain/moon/commands.md:436 +#: ../../toolchain/moon/commands.md:448 msgid "`moon shell-completion`" msgstr "" -#: ../../toolchain/moon/commands.md:438 +#: ../../toolchain/moon/commands.md:450 msgid "Generate shell completion for bash/elvish/fish/pwsh/zsh to stdout" msgstr "" -#: ../../toolchain/moon/commands.md:440 +#: ../../toolchain/moon/commands.md:452 msgid "**Usage:** `moon shell-completion [OPTIONS]`" msgstr "" -#: ../../toolchain/moon/commands.md:443 +#: ../../toolchain/moon/commands.md:455 msgid "" "Discussion: Enable tab completion for Bash, Elvish, Fish, Zsh, or " "PowerShell The script is output on `stdout`, allowing one to re-direct " @@ -886,7 +900,7 @@ msgid "" "be placed." msgstr "" -#: ../../toolchain/moon/commands.md:451 +#: ../../toolchain/moon/commands.md:463 msgid "" "The completion scripts won't update itself, so you may need to " "periodically run this command to get the latest completions. Or you may " @@ -895,107 +909,107 @@ msgid "" "considered not as efficient as having the completions script installed." msgstr "" -#: ../../toolchain/moon/commands.md:458 +#: ../../toolchain/moon/commands.md:470 msgid "" "Here are some common set ups for the three supported shells under Unix " "and similar operating systems (such as GNU/Linux)." msgstr "" -#: ../../toolchain/moon/commands.md:461 +#: ../../toolchain/moon/commands.md:473 msgid "Bash:" msgstr "" -#: ../../toolchain/moon/commands.md:463 +#: ../../toolchain/moon/commands.md:475 msgid "" "Completion files are commonly stored in `/etc/bash_completion.d/` for " "system-wide commands, but can be stored in `~/.local/share/bash-" "completion/completions` for user-specific commands. Run the command:" msgstr "" -#: ../../toolchain/moon/commands.md:468 +#: ../../toolchain/moon/commands.md:480 msgid "" "$ mkdir -p ~/.local/share/bash-completion/completions\n" "$ moon shell-completion --shell bash >> ~/.local/share/bash-" "completion/completions/moon\n" msgstr "" -#: ../../toolchain/moon/commands.md:471 ../../toolchain/moon/commands.md:490 +#: ../../toolchain/moon/commands.md:483 ../../toolchain/moon/commands.md:502 msgid "" "This installs the completion script. You may have to log out and log back" " in to your shell session for the changes to take effect." msgstr "" -#: ../../toolchain/moon/commands.md:474 +#: ../../toolchain/moon/commands.md:486 msgid "Bash (macOS/Homebrew):" msgstr "" -#: ../../toolchain/moon/commands.md:476 +#: ../../toolchain/moon/commands.md:488 msgid "" "Homebrew stores bash completion files within the Homebrew directory. With" " the `bash-completion` brew formula installed, run the command:" msgstr "" -#: ../../toolchain/moon/commands.md:479 +#: ../../toolchain/moon/commands.md:491 msgid "" "$ mkdir -p $(brew --prefix)/etc/bash_completion.d\n" "$ moon shell-completion --shell bash > $(brew " "--prefix)/etc/bash_completion.d/moon.bash-completion\n" msgstr "" -#: ../../toolchain/moon/commands.md:482 +#: ../../toolchain/moon/commands.md:494 msgid "Fish:" msgstr "" -#: ../../toolchain/moon/commands.md:484 +#: ../../toolchain/moon/commands.md:496 msgid "" "Fish completion files are commonly stored in " "`$HOME/.config/fish/completions`. Run the command:" msgstr "" -#: ../../toolchain/moon/commands.md:487 +#: ../../toolchain/moon/commands.md:499 msgid "" "$ mkdir -p ~/.config/fish/completions\n" "$ moon shell-completion --shell fish > " "~/.config/fish/completions/moon.fish\n" msgstr "" -#: ../../toolchain/moon/commands.md:493 +#: ../../toolchain/moon/commands.md:505 msgid "Elvish:" msgstr "" -#: ../../toolchain/moon/commands.md:495 +#: ../../toolchain/moon/commands.md:507 msgid "" "Elvish completions are commonly stored in a single `completers` module. A" " typical module search path is `~/.config/elvish/lib`, and running the " "command:" msgstr "" -#: ../../toolchain/moon/commands.md:499 +#: ../../toolchain/moon/commands.md:511 msgid "" "$ moon shell-completion --shell elvish >> " "~/.config/elvish/lib/completers.elv\n" msgstr "" -#: ../../toolchain/moon/commands.md:501 +#: ../../toolchain/moon/commands.md:513 msgid "" "will install the completions script. Note that use `>>` (append) instead" " of `>` (overwrite) to prevent overwriting the existing completions for " "other commands. Then prepend your rc.elv with:" msgstr "" -#: ../../toolchain/moon/commands.md:505 +#: ../../toolchain/moon/commands.md:517 msgid "`use completers`\n" msgstr "" -#: ../../toolchain/moon/commands.md:507 +#: ../../toolchain/moon/commands.md:519 msgid "to load the `completers` module and enable completions." msgstr "" -#: ../../toolchain/moon/commands.md:509 +#: ../../toolchain/moon/commands.md:521 msgid "Zsh:" msgstr "" -#: ../../toolchain/moon/commands.md:511 +#: ../../toolchain/moon/commands.md:523 msgid "" "ZSH completions are commonly stored in any directory listed in your " "`$fpath` variable. To use these completions, you must either add the " @@ -1003,50 +1017,50 @@ msgid "" "list." msgstr "" -#: ../../toolchain/moon/commands.md:516 +#: ../../toolchain/moon/commands.md:528 msgid "" "Adding a custom directory is often the safest bet if you are unsure of " "which directory to use. First create the directory; for this example " "we'll create a hidden directory inside our `$HOME` directory:" msgstr "" -#: ../../toolchain/moon/commands.md:521 +#: ../../toolchain/moon/commands.md:533 msgid "$ mkdir ~/.zfunc\n" msgstr "" -#: ../../toolchain/moon/commands.md:523 +#: ../../toolchain/moon/commands.md:535 msgid "Then add the following lines to your `.zshrc` just before `compinit`:" msgstr "" -#: ../../toolchain/moon/commands.md:526 +#: ../../toolchain/moon/commands.md:538 msgid "fpath+=~/.zfunc\n" msgstr "" -#: ../../toolchain/moon/commands.md:528 +#: ../../toolchain/moon/commands.md:540 msgid "Now you can install the completions script using the following command:" msgstr "" -#: ../../toolchain/moon/commands.md:531 +#: ../../toolchain/moon/commands.md:543 msgid "$ moon shell-completion --shell zsh > ~/.zfunc/_moon\n" msgstr "" -#: ../../toolchain/moon/commands.md:533 +#: ../../toolchain/moon/commands.md:545 msgid "You must then open a new zsh session, or simply run" msgstr "" -#: ../../toolchain/moon/commands.md:535 +#: ../../toolchain/moon/commands.md:547 msgid "$ . ~/.zshrc\n" msgstr "" -#: ../../toolchain/moon/commands.md:537 +#: ../../toolchain/moon/commands.md:549 msgid "for the new completions to take effect." msgstr "" -#: ../../toolchain/moon/commands.md:539 +#: ../../toolchain/moon/commands.md:551 msgid "Custom locations:" msgstr "" -#: ../../toolchain/moon/commands.md:541 +#: ../../toolchain/moon/commands.md:553 msgid "" "Alternatively, you could save these files to the place of your choosing, " "such as a custom directory inside your $HOME. Doing so will require you " @@ -1054,96 +1068,96 @@ msgid "" "script. Consult your shells documentation for how to add such directives." msgstr "" -#: ../../toolchain/moon/commands.md:547 +#: ../../toolchain/moon/commands.md:559 msgid "PowerShell:" msgstr "" -#: ../../toolchain/moon/commands.md:549 +#: ../../toolchain/moon/commands.md:561 msgid "" "The powershell completion scripts require PowerShell v5.0+ (which comes " "with Windows 10, but can be downloaded separately for windows 7 or 8.1)." msgstr "" -#: ../../toolchain/moon/commands.md:553 +#: ../../toolchain/moon/commands.md:565 msgid "First, check if a profile has already been set" msgstr "" -#: ../../toolchain/moon/commands.md:555 +#: ../../toolchain/moon/commands.md:567 msgid "PS C:\\> Test-Path $profile\n" msgstr "" -#: ../../toolchain/moon/commands.md:557 +#: ../../toolchain/moon/commands.md:569 msgid "If the above command returns `False` run the following" msgstr "" -#: ../../toolchain/moon/commands.md:559 +#: ../../toolchain/moon/commands.md:571 msgid "PS C:\\> New-Item -path $profile -type file -force\n" msgstr "" -#: ../../toolchain/moon/commands.md:561 +#: ../../toolchain/moon/commands.md:573 msgid "" "Now open the file provided by `$profile` (if you used the `New-Item` " "command it will be " "`${env:USERPROFILE}\\Documents\\WindowsPowerShell\\Microsoft.PowerShell_profile.ps1`" msgstr "" -#: ../../toolchain/moon/commands.md:565 +#: ../../toolchain/moon/commands.md:577 msgid "" "Next, we either save the completions file into our profile, or into a " "separate file and source it inside our profile. To save the completions " "into our profile simply use" msgstr "" -#: ../../toolchain/moon/commands.md:569 +#: ../../toolchain/moon/commands.md:581 msgid "" "PS C:\\> moon shell-completion --shell powershell >>\n" "${env:USERPROFILE}\\Documents\\WindowsPowerShell\\Microsoft.PowerShell_profile.ps1" "\n" msgstr "" -#: ../../toolchain/moon/commands.md:572 +#: ../../toolchain/moon/commands.md:584 msgid "" "This discussion is taken from `rustup completions` command with some " "changes." msgstr "" -#: ../../toolchain/moon/commands.md:577 +#: ../../toolchain/moon/commands.md:589 msgid "`--shell ` — The shell to generate completion for" msgstr "" -#: ../../toolchain/moon/commands.md:579 +#: ../../toolchain/moon/commands.md:591 msgid "Default value: ``" msgstr "" -#: ../../toolchain/moon/commands.md:581 +#: ../../toolchain/moon/commands.md:593 msgid "Possible values: `bash`, `elvish`, `fish`, `powershell`, `zsh`" msgstr "" -#: ../../toolchain/moon/commands.md:586 +#: ../../toolchain/moon/commands.md:598 msgid "`moon version`" msgstr "" -#: ../../toolchain/moon/commands.md:588 +#: ../../toolchain/moon/commands.md:600 msgid "Print version information and exit" msgstr "" -#: ../../toolchain/moon/commands.md:590 +#: ../../toolchain/moon/commands.md:602 msgid "**Usage:** `moon version [OPTIONS]`" msgstr "" -#: ../../toolchain/moon/commands.md:594 +#: ../../toolchain/moon/commands.md:606 msgid "`--all` — Print all version information" msgstr "" -#: ../../toolchain/moon/commands.md:595 +#: ../../toolchain/moon/commands.md:607 msgid "`--json` — Print version information in JSON format" msgstr "" -#: ../../toolchain/moon/commands.md:596 +#: ../../toolchain/moon/commands.md:608 msgid "`--no-path` — Do not print the path" msgstr "" -#: ../../toolchain/moon/commands.md:602 +#: ../../toolchain/moon/commands.md:614 msgid "" " This document was generated automatically by clap-" @@ -2687,3 +2701,7 @@ msgid "" "test username/hello/lib/fib/fib_test.mbt::0 ok\n" "Total tests: 3, passed: 3, failed: 0.\n" msgstr "" + +#~ msgid "**Usage:** `moon add `" +#~ msgstr "" + diff --git a/next/locales/zh_CN/LC_MESSAGES/tutorial.po b/next/locales/zh_CN/LC_MESSAGES/tutorial.po index 35b73e4c..aa7669f8 100644 --- a/next/locales/zh_CN/LC_MESSAGES/tutorial.po +++ b/next/locales/zh_CN/LC_MESSAGES/tutorial.po @@ -9,7 +9,7 @@ msgid "" msgstr "" "Project-Id-Version: MoonBit Document \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-12-04 11:42+0800\n" +"POT-Creation-Date: 2024-12-18 11:20+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: zh_CN\n" @@ -26,16 +26,10 @@ msgstr "" #: ../../tutorial/example/gmachine/gmachine-1.md:3 msgid "" -"Lazy evaluation stands as a foundational concept in the realm of " -"programming languages. Haskell, renowned as a purely functional " -"programming language, boasts a robust lazy evaluation mechanism. This " -"mechanism not only empowers developers to craft code that's both more " -"efficient and concise but also enhances program performance and " -"responsiveness, especially when tackling sizable datasets or intricate " -"data streams. In this article, we'll delve into the Lazy Evaluation " -"mechanism, thoroughly examining its principles and implementation " -"methods, and then explore how to implement Haskell's evaluation semantics" -" in [MoonBit](https://www.moonbitlang.com/)." +"This article is the first in the series on implementing lazy evaluation " +"in MoonBit. In this article, we will exploring the purposes of lazy " +"evaluation and a typical abstract machine for lazy evaluation, the " +"G-Machine." msgstr "" #: ../../tutorial/example/gmachine/gmachine-1.md:5 @@ -267,7 +261,7 @@ msgid "" "enum RawExpr[T] {\n" " Var(T)\n" " Num(Int)\n" -" Constructor(Int, Int) // tag, arity\n" +" Constructor(tag~:Int, arity~:Int) // tag, arity\n" " App(RawExpr[T], RawExpr[T])\n" " Let(Bool, List[(T, RawExpr[T])], RawExpr[T]) // isRec, Defs, Body\n" " Case(RawExpr[T], List[(Int, List[T], RawExpr[T])])\n" @@ -280,88 +274,100 @@ msgid "" "} derive(Show)\n" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:123 +#: ../../tutorial/example/gmachine/gmachine-1.md:112 msgid "Additionally, some predefined coreF programs are required." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:125 -msgid "" -"let preludeDefs : List[ScDef[String]] = {\n" -" let id = ScDef::new(\"I\", List::of([\"x\"]), Var(\"x\")) // id x = x\n" -" let k = ScDef::new(\"K\", List::of([\"x\", \"y\"]), Var(\"x\")) // K x " -"y = x\n" -" let k1 = ScDef::new(\"K1\", List::of([\"x\", \"y\"]), Var(\"y\")) // K1" -" x y = y\n" -" let s = ScDef::new(\n" -" \"S\",\n" -" List::of([\"f\", \"g\", \"x\"]),\n" -" App(App(Var(\"f\"), Var(\"x\")), App(Var(\"g\"), Var(\"x\"))),\n" -" ) // S f g x = f x (g x)\n" -" let compose = ScDef::new(\n" -" \"compose\",\n" -" List::of([\"f\", \"g\", \"x\"]),\n" -" App(Var(\"f\"), App(Var(\"g\"), Var(\"x\"))),\n" -" ) // compose f g x = f (g x)\n" -" let twice = ScDef::new(\n" -" \"twice\",\n" -" List::of([\"f\"]),\n" -" App(App(Var(\"compose\"), Var(\"f\")), Var(\"f\")),\n" -" ) // twice f = compose f f\n" -" Cons(id, Cons(k, Cons(k1, Cons(s, Cons(compose, Cons(twice, Nil))))))\n" -"}\n" -msgstr "" - -#: ../../tutorial/example/gmachine/gmachine-1.md:149 +#: ../../tutorial/example/gmachine/gmachine-1.md:114 +msgid "" +"let prelude_defs : List[ScDef[String]] = {\n" +" let args : (FixedArray[String]) -> List[String] = List::of\n" +" let id = ScDef::new(\"I\", args([\"x\"]), Var(\"x\")) // id x = x\n" +" let k = \n" +" ScDef::new(\n" +" \"K\",\n" +" args([\"x\", \"y\"]),\n" +" Var(\"x\")\n" +" ) // K x y = x\n" +" let k1 = \n" +" ScDef::new(\n" +" \"K1\",\n" +" args([\"x\", \"y\"]),\n" +" Var(\"y\")\n" +" ) // K1 x y = y\n" +" let s = \n" +" ScDef::new(\n" +" \"S\",\n" +" args([\"f\", \"g\", \"x\"]),\n" +" App(App(Var(\"f\"), Var(\"x\")), App(Var(\"g\"), Var(\"x\")))\n" +" ) // S f g x = f x (g x)\n" +" let compose = \n" +" ScDef::new(\n" +" \"compose\",\n" +" args([\"f\", \"g\", \"x\"]),\n" +" App(Var(\"f\"), App(Var(\"g\"), Var(\"x\")))\n" +" ) // compose f g x = f (g x)\n" +" let twice = \n" +" ScDef::new(\n" +" \"twice\",\n" +" args([\"f\"]),\n" +" App(App(Var(\"compose\"), Var(\"f\")), Var(\"f\"))\n" +" ) // twice f = compose f f\n" +" List::of([id, k, k1, s, compose, twice])\n" +"}\n" +msgstr "" + +#: ../../tutorial/example/gmachine/gmachine-1.md:120 msgid "Why Graph" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:151 +#: ../../tutorial/example/gmachine/gmachine-1.md:122 msgid "" "In the coreF language, expressions (not `RawExpr[T]` mentioned earlier, " "but runtime expressions) are stored in memory in the form of a graph " "rather than a tree when being evaluated.)" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:153 +#: ../../tutorial/example/gmachine/gmachine-1.md:124 msgid "Why is this approach taken? Let's examine this through a program example:" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:155 +#: ../../tutorial/example/gmachine/gmachine-1.md:126 msgid "" "(defn square[x] (mul x x))\n" "(defn main[] (square (square 3)))\n" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:160 +#: ../../tutorial/example/gmachine/gmachine-1.md:131 msgid "" "If we evaluate according to the conventional expression tree, it would be" " reduced to:" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:162 +#: ../../tutorial/example/gmachine/gmachine-1.md:133 msgid "(mul (square 3) (square 3))\n" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:166 +#: ../../tutorial/example/gmachine/gmachine-1.md:137 msgid "" "In this case, `(square 3)` would be evaluated twice, which is certainly " "not desirable for lazy evaluation." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:168 +#: ../../tutorial/example/gmachine/gmachine-1.md:139 msgid "" "To illustrate this more clearly, let's make a somewhat improper analogy " "using MoonBit code:" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:170 +#: ../../tutorial/example/gmachine/gmachine-1.md:141 msgid "" "fn square(thunk : () -> Int) -> Int {\n" " thunk() * thunk()\n" "}\n" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:176 +#: ../../tutorial/example/gmachine/gmachine-1.md:147 msgid "" "To represent the program using a graph is to facilitate sharing of " "computation results and avoid redundant calculations. To achieve this " @@ -370,7 +376,7 @@ msgid "" "MoonBit code:" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:178 +#: ../../tutorial/example/gmachine/gmachine-1.md:149 msgid "" "enum LazyData[T] {\n" " Waiting(() -> T)\n" @@ -397,7 +403,7 @@ msgid "" "}\n" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:204 +#: ../../tutorial/example/gmachine/gmachine-1.md:155 msgid "" "Regardless of which side executes the `extract` method first, it will " "update the referenced mutable field and replace its content with the " @@ -405,34 +411,34 @@ msgid "" "second execution of the `extract` method." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:206 +#: ../../tutorial/example/gmachine/gmachine-1.md:157 msgid "Conventions" msgstr "约定:" -#: ../../tutorial/example/gmachine/gmachine-1.md:208 +#: ../../tutorial/example/gmachine/gmachine-1.md:159 msgid "" "Before delving into how graph reduction works, let's establish some key " "terms and basic facts. We'll continue using the same program as an " "example:" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:210 +#: ../../tutorial/example/gmachine/gmachine-1.md:161 msgid "" "(defn square[x] (mul x x)) ;; multiplication\n" "(defn main[] (square (square 3)))\n" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:215 +#: ../../tutorial/example/gmachine/gmachine-1.md:166 msgid "Built-in primitives like `mul` are predefined operations." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:217 +#: ../../tutorial/example/gmachine/gmachine-1.md:168 msgid "" "Evaluating an expression (of course, lazy) and updating its corresponding" " node in the graph in place is called reduction." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:218 +#: ../../tutorial/example/gmachine/gmachine-1.md:169 msgid "" "`(square 3)` is a reducible expression (often abbreviated as redex), " "consisting of `square` and its argument. It can be reduced to `(mul 3 " @@ -441,32 +447,32 @@ msgid "" "while `mul` is an implemented built-in primitive." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:219 +#: ../../tutorial/example/gmachine/gmachine-1.md:170 msgid "" "The reduction result of `(mul 3 3)` is the expression `9`, which cannot " "be further reduced. Such expressions that cannot be further reduced are " "called Normal forms." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:220 +#: ../../tutorial/example/gmachine/gmachine-1.md:171 msgid "" "An expression may contain multiple sub-expressions (e.g., `(mul (add 3 5)" " (mul 7 9))`). In such cases, the order of reduction of expressions is " "crucial – some programs only halt under specific reduction orders." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:222 +#: ../../tutorial/example/gmachine/gmachine-1.md:173 msgid "" "There's a special reduction order that always selects the outermost redex" " for reduction, known as _normal order reduction_. This reduction order " "will be uniformly adopted in the following discussion." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:224 +#: ../../tutorial/example/gmachine/gmachine-1.md:175 msgid "So, the graph reduction can be described with the following pseudocode:" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:226 +#: ../../tutorial/example/gmachine/gmachine-1.md:177 msgid "" "While there exist reducible expressions in the graph {\n" " Select the outermost reducible expression.\n" @@ -475,44 +481,44 @@ msgid "" "}\n" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:234 +#: ../../tutorial/example/gmachine/gmachine-1.md:185 msgid "" "Dizzy now? Let's find a few examples to demonstrate how to perform " "reductions on paper." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:236 +#: ../../tutorial/example/gmachine/gmachine-1.md:187 msgid "**Step 1: Find the next redex**" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:238 +#: ../../tutorial/example/gmachine/gmachine-1.md:189 msgid "The execution of the entire program starts from the `main` function." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:240 +#: ../../tutorial/example/gmachine/gmachine-1.md:191 msgid "" "(defn square[x] (mul x x))\n" "(defn main[] (add 33 (square 3)))\n" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:245 +#: ../../tutorial/example/gmachine/gmachine-1.md:196 msgid "" "`main` itself is a CAF - the simplest kind of redex. If we perform the " "substitution, the current expression to be handled is:" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:247 +#: ../../tutorial/example/gmachine/gmachine-1.md:198 msgid "(add 33 (square 3))\n" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:251 +#: ../../tutorial/example/gmachine/gmachine-1.md:202 msgid "" "According to the principle of finding the outermost redex, it seems like " "we've immediately found the redex formed by `add` and its two parameters " "(let's assume it for now)." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:253 +#: ../../tutorial/example/gmachine/gmachine-1.md:204 msgid "" "But wait! Due to the presence of default currying, the abstract syntax " "tree corresponding to this expression is actually composed of multiple " @@ -520,17 +526,17 @@ msgid "" "readability):" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:255 +#: ../../tutorial/example/gmachine/gmachine-1.md:206 msgid "App(App(add, 33), square3)\n" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:259 +#: ../../tutorial/example/gmachine/gmachine-1.md:210 msgid "" "This chain-like structure from `add` to the outermost `App` node is " "called the \"Spine\"" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:261 +#: ../../tutorial/example/gmachine/gmachine-1.md:212 msgid "" "Going back to check, `add` is an internally defined primitive. However, " "since its second argument `(square 3)` is not in normal form, we cannot " @@ -540,28 +546,28 @@ msgid "" "must first reduce `(square 3)`." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:263 +#: ../../tutorial/example/gmachine/gmachine-1.md:214 msgid "**Step 2: Reduce**" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:265 +#: ../../tutorial/example/gmachine/gmachine-1.md:216 msgid "" "Since `square` is a user-defined super combinator, reducing `(square 3)` " "involves only parameter substitution." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:267 +#: ../../tutorial/example/gmachine/gmachine-1.md:218 msgid "" "If a redex has fewer arguments than required by the super combinator, " "which is common in higher-order functions, consider the example of " "tripling all integers in a list." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:269 +#: ../../tutorial/example/gmachine/gmachine-1.md:220 msgid "(map (mul 3) list-of-int)\n" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:273 +#: ../../tutorial/example/gmachine/gmachine-1.md:224 msgid "" "Here, `(mul 3)` cannot be treated as a redex because it lacks sufficient " "arguments, making it a `weak head normal form` (often abbreviated as " @@ -569,48 +575,48 @@ msgid "" " action is needed." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:275 +#: ../../tutorial/example/gmachine/gmachine-1.md:226 msgid "**Step 3: Update**" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:277 +#: ../../tutorial/example/gmachine/gmachine-1.md:228 msgid "" "This step only affects execution efficiency and can be skipped during " "paper deductions." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:279 +#: ../../tutorial/example/gmachine/gmachine-1.md:230 msgid "" "These operations are easy to perform on paper (when the amount of code " "doesn't exceed half a sheet), but when we switch to computers, how do we " "translate these steps into executable code?" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:281 +#: ../../tutorial/example/gmachine/gmachine-1.md:232 msgid "" "To answer this question, pioneers in the world of lazy evaluation " "programming languages have proposed various **abstract machines** for " "modeling lazy evaluation. These include:" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:283 +#: ../../tutorial/example/gmachine/gmachine-1.md:234 #: ../../tutorial/example/gmachine/index.md:1 msgid "G-Machine" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:284 +#: ../../tutorial/example/gmachine/gmachine-1.md:235 msgid "Three Instruction Machine" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:285 +#: ../../tutorial/example/gmachine/gmachine-1.md:236 msgid "ABC Machine (used by the Clean language)" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:286 +#: ../../tutorial/example/gmachine/gmachine-1.md:237 msgid "Spineless Tagless G-Machine (abbreviated as STG, used by Haskell language)" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:288 +#: ../../tutorial/example/gmachine/gmachine-1.md:239 msgid "" "They are execution models used to guide compiler implementations. It's " "important to note that, unlike various popular virtual machines today " @@ -622,18 +628,18 @@ msgid "" "selected backend." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:290 +#: ../../tutorial/example/gmachine/gmachine-1.md:241 msgid "" "To simplify implementation, this article will directly use MoonBit to " "write an interpreter for G-Machine instructions, starting from a minimal " "example and gradually adding more features." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:292 +#: ../../tutorial/example/gmachine/gmachine-1.md:243 msgid "G-Machine Overview" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:294 +#: ../../tutorial/example/gmachine/gmachine-1.md:245 msgid "" "While the G-Machine is an abstract machine for lazy functional languages," " its structure and concepts are not significantly different from what one" @@ -642,111 +648,118 @@ msgid "" "sequentially. Some key differences include:" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:296 +#: ../../tutorial/example/gmachine/gmachine-1.md:247 msgid "The basic unit of memory in the heap is not bytes, but graph nodes." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:297 +#: ../../tutorial/example/gmachine/gmachine-1.md:248 msgid "" "The stack only contains pointers to addresses in the heap, not actual " "data." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:299 +#: ../../tutorial/example/gmachine/gmachine-1.md:250 msgid "This design may not be practical, but it's relatively simple." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:301 +#: ../../tutorial/example/gmachine/gmachine-1.md:252 msgid "" "In coreF, super combinators are compiled into a series of G-Machine " "instructions. These instructions can be roughly categorized as follows:" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:303 +#: ../../tutorial/example/gmachine/gmachine-1.md:254 msgid "" "Access Data Instructions, For example, `PushArg` (access function " "arguments), and `PushGlobal` (access other super combinators)." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:304 +#: ../../tutorial/example/gmachine/gmachine-1.md:255 msgid "" "Construct/update graph nodes in the heap, like `MkApp`, `PushInt`, " "`Update`" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:305 +#: ../../tutorial/example/gmachine/gmachine-1.md:256 msgid "Clean up the `Pop` instruction of the unused addresses from the stack." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:306 +#: ../../tutorial/example/gmachine/gmachine-1.md:257 msgid "Express control flow with the `Unwind` instruction" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:308 +#: ../../tutorial/example/gmachine/gmachine-1.md:259 msgid "Dissecting the G-Machine State" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:310 +#: ../../tutorial/example/gmachine/gmachine-1.md:261 msgid "In this simple version of the G-Machine, the state includes:" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:312 +#: ../../tutorial/example/gmachine/gmachine-1.md:263 msgid "" "Heap: This is where the expression graph and the sequences of " "instructions corresponding to super combinators are stored." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:314 +#: ../../tutorial/example/gmachine/gmachine-1.md:265 #, python-format msgid "" "// Use the 'type' keyword to encapsulate an address type.\n" -"type Addr Int derive(Eq, Show) \n" +"type Addr Int derive(Eq, Show)\n" "\n" "// Describe graph nodes with an enumeration type.\n" -"enum Node { \n" +"enum Node {\n" " NNum(Int)\n" " // The application node\n" -" NApp(Addr, Addr) \n" +" NApp(Addr, Addr)\n" " // To store the number of parameters and \n" -" // the corresponding sequence of instructions for a super combinator.\n" -" NGlobal(String, Int, List[Instruction]) \n" +" // the corresponding sequence of instructions for a super combinator\n" +" NGlobal(String, Int, List[Instruction])\n" " // The Indirection node,The key component of implementing lazy " "evaluation\n" -" NInd(Addr) \n" -"} derive (Eq, Show)\n" +" NInd(Addr)\n" +"} derive(Eq, Show)\n" "\n" -"struct GHeap { // The heap uses an array, and the space with None content" -" in the array is available as free memory.\n" -" mut objectCount : Int\n" -" memory : Array[Option[Node]]\n" +"struct GHeap {\n" +" // The heap uses an array, \n" +" // and the space with None content in the array is available as free " +"memory.\n" +" mut object_count : Int\n" +" memory : Array[Node?]\n" "}\n" "\n" "// Allocate heap space for nodes.\n" "fn alloc(self : GHeap, node : Node) -> Addr {\n" " let heap = self\n" -" // Assuming there is still available space in the heap.\n" " fn next(n : Int) -> Int {\n" " (n + 1) % heap.memory.length()\n" " }\n" +"\n" " fn free(i : Int) -> Bool {\n" -" heap.memory[i].is_empty()\n" +" match heap.memory[i] {\n" +" None => true\n" +" _ => false\n" +" }\n" " }\n" -" let mut i = heap.objectCount\n" +"\n" +" let mut i = heap.object_count\n" " while not(free(i)) {\n" " i = next(i)\n" " }\n" " heap.memory[i] = Some(node)\n" +" heap.object_count = heap.object_count + 1\n" " return Addr(i)\n" "}\n" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:354 +#: ../../tutorial/example/gmachine/gmachine-1.md:271 msgid "" "Stack: The stack only holds addresses pointing to the heap. A simple " "implementation can use `List[Addr]`." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:355 +#: ../../tutorial/example/gmachine/gmachine-1.md:272 msgid "" "Global Table: It's a mapping table that records the names of super " "combinators (including predefined and user-defined) and their " @@ -754,53 +767,42 @@ msgid "" "Robin Hood hash table." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:356 +#: ../../tutorial/example/gmachine/gmachine-1.md:273 msgid "Current code sequence to be executed." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:357 +#: ../../tutorial/example/gmachine/gmachine-1.md:274 msgid "" "Execution status statistics: A simple implementation involves calculating" " how many instructions have been executed." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:359 -msgid "" -"type GStats Int\n" -"\n" -"let statInitial : GStats = GStats(0)\n" -"\n" -"fn statInc(self : GStats) -> GStats {\n" -" let GStats(n) = self\n" -" GStats(n + 1)\n" -"}\n" -"\n" -"fn statGet(self : GStats) -> Int {\n" -" let GStats(n) = self\n" -" return n\n" -"}\n" -msgstr "" - -#: ../../tutorial/example/gmachine/gmachine-1.md:375 +#: ../../tutorial/example/gmachine/gmachine-1.md:276 msgid "The entire state is represented using the type `GState`." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:377 +#: ../../tutorial/example/gmachine/gmachine-1.md:278 msgid "" "struct GState {\n" " mut stack : List[Addr]\n" " heap : GHeap\n" -" globals : RHTable[String, Addr]\n" +" globals : @hashmap.T[String, Addr]\n" " mut code : List[Instruction]\n" -" stats : GStats\n" +" mut stats : GStats\n" "}\n" "\n" -"fn putStack(self : GState, addr : Addr) -> Unit {\n" +"type GStats Int\n" +"\n" +"fn stat_incr(self : GState) -> Unit {\n" +" self.stats = self.stats._ + 1\n" +"}\n" +"\n" +"fn put_stack(self : GState, addr : Addr) -> Unit {\n" " self.stack = Cons(addr, self.stack)\n" "}\n" "\n" -"fn putCode(self : GState, is : List[Instruction]) -> Unit {\n" -" self.code = append(is, self.code)\n" +"fn put_code(self : GState, instrs : List[Instruction]) -> Unit {\n" +" self.code = instrs + self.code\n" "}\n" "\n" "fn pop1(self : GState) -> Addr {\n" @@ -809,36 +811,31 @@ msgid "" " self.stack = reststack\n" " addr\n" " }\n" -" Nil => {\n" -" abort(\"pop1: stack size smaller than 1\")\n" -" }\n" +" Nil => abort(\"pop1(): stack size smaller than 1\")\n" " }\n" "}\n" "\n" +"// e1 e2 ..... -> (e1, e2) ......\n" "fn pop2(self : GState) -> (Addr, Addr) {\n" -" // Pop 2 pops the top two elements from the stack.\n" -" // Returns (the first, the second).\n" " match self.stack {\n" " Cons(addr1, Cons(addr2, reststack)) => {\n" " self.stack = reststack\n" " (addr1, addr2)\n" " }\n" -" otherwise => {\n" -" abort(\"pop2: stack size smaller than 2\")\n" -" }\n" +" _ => abort(\"pop2(): stack size smaller than 2\")\n" " }\n" "}\n" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:421 -#: ../../tutorial/example/gmachine/gmachine-1.md:427 +#: ../../tutorial/example/gmachine/gmachine-1.md:284 +#: ../../tutorial/example/gmachine/gmachine-1.md:290 msgid "" "Now, we can map each step of the graph reduction algorithm we deduced on " "paper to this abstract machine:" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:423 -#: ../../tutorial/example/gmachine/gmachine-1.md:429 +#: ../../tutorial/example/gmachine/gmachine-1.md:286 +#: ../../tutorial/example/gmachine/gmachine-1.md:292 msgid "" "At the initial state of the machine, all compiled super combinators have " "been placed in `NGlobal` nodes on the heap. At this point, the current " @@ -848,8 +845,8 @@ msgid "" "the current code sequence." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:424 -#: ../../tutorial/example/gmachine/gmachine-1.md:430 +#: ../../tutorial/example/gmachine/gmachine-1.md:287 +#: ../../tutorial/example/gmachine/gmachine-1.md:293 msgid "" "The corresponding code sequence of `main` is instantiated on the heap, " "where nodes are allocated and data is loaded accordingly, ultimately " @@ -858,14 +855,14 @@ msgid "" "the entry point of this graph is pushed onto the stack." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:425 +#: ../../tutorial/example/gmachine/gmachine-1.md:288 msgid "" "After instantiation is finished, you need to update graph nodes (since " "`main` has no parameters, there is no need to clean up residual unused " "addresses in the stack) and find the next redex to clean up." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:431 +#: ../../tutorial/example/gmachine/gmachine-1.md:294 msgid "" "After instantiation is finished, cleanup work is done, which involves " "updating graph nodes (since `main` has no parameters, there is no need to" @@ -873,19 +870,19 @@ msgid "" "redex." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:433 +#: ../../tutorial/example/gmachine/gmachine-1.md:296 msgid "All of these tasks have corresponding instruction implementations." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:435 +#: ../../tutorial/example/gmachine/gmachine-1.md:298 msgid "Corresponding Effect of Each Instruction" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:437 +#: ../../tutorial/example/gmachine/gmachine-1.md:300 msgid "The highly simplified G-Machine currently consists of 7 instructions." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:439 +#: ../../tutorial/example/gmachine/gmachine-1.md:302 msgid "" "enum Instruction {\n" " Unwind\n" @@ -895,45 +892,42 @@ msgid "" " MkApp\n" " Update(Int)\n" " Pop(Int)\n" -"} derive(Eq, Show)\n" +"} derive (Eq, Show)\n" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:451 +#: ../../tutorial/example/gmachine/gmachine-1.md:308 msgid "" "The `PushInt` instruction is the simplest. It allocates an `NNum` node on" " the heap and pushes its address onto the stack." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:453 +#: ../../tutorial/example/gmachine/gmachine-1.md:310 msgid "" "fn push_int(self : GState, num : Int) -> Unit {\n" " let addr = self.heap.alloc(NNum(num))\n" -" self.putStack(addr)\n" +" self.put_stack(addr)\n" "}\n" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:460 +#: ../../tutorial/example/gmachine/gmachine-1.md:316 msgid "" "The `PushGlobal` instruction retrieves the address of the specified super" " combinator from the global table and then pushes the address onto the " "stack." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:462 +#: ../../tutorial/example/gmachine/gmachine-1.md:318 msgid "" "fn push_global(self : GState, name : String) -> Unit {\n" " let sc = self.globals[name]\n" " match sc {\n" -" None => abort(\"push_global(): cant find super combinator \\{name}\")" -"\n" -" Some(addr) => {\n" -" self.putStack(addr)\n" -" }\n" +" None => abort(\"push_global(): cant find supercombinator \\{name}\")\n" +" Some(addr) => self.put_stack(addr)\n" " }\n" "}\n" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:474 +#: ../../tutorial/example/gmachine/gmachine-1.md:324 msgid "" "The `PushArg` instruction is a bit more complex. It has specific " "requirements regarding the layout of addresses on the stack: the first " @@ -942,40 +936,38 @@ msgid "" "parameter, starting from the `offset + 1`." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:476 +#: ../../tutorial/example/gmachine/gmachine-1.md:326 msgid "" "fn push_arg(self : GState, offset : Int) -> Unit {\n" -" // Skip the first super combinator node.\n" -" // Access the (offset + 1)th NApp node\n" -" let appaddr = @immut/list.unsafe_nth(self.stack, offset + 1)\n" +" let appaddr = self.stack.unsafe_nth(offset + 1)\n" " let arg = match self.heap[appaddr] {\n" " NApp(_, arg) => arg\n" -" otherwise => \n" +" otherwise =>\n" " abort(\n" -" \"push_arg: stack offset \\{offset} address \\{appaddr} node " -"\\{otherwise}, not a applicative node\"\n" +" \"pusharg: stack offset \\{offset} address \\{appaddr} node " +"\\{otherwise}\",\n" " )\n" " }\n" -" self.putStack(arg)\n" +" self.put_stack(arg)\n" "}\n" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:492 +#: ../../tutorial/example/gmachine/gmachine-1.md:332 msgid "" "The `MkApp` instruction takes two addresses from the top of the stack, " "constructs an `NApp` node, and pushes its address onto the stack." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:494 +#: ../../tutorial/example/gmachine/gmachine-1.md:334 msgid "" -"fn mkapp(self : GState) -> Unit {\n" +"fn mk_apply(self : GState) -> Unit {\n" " let (a1, a2) = self.pop2()\n" " let appaddr = self.heap.alloc(NApp(a1, a2))\n" -" self.putStack(appaddr)\n" +" self.put_stack(appaddr)\n" "}\n" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:502 +#: ../../tutorial/example/gmachine/gmachine-1.md:340 msgid "" "The `Update` instruction assumes that the first address on the stack " "points to the current redex's evaluation result. It skips the addresses " @@ -987,105 +979,101 @@ msgid "" "parameters and ordinary variables." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:504 +#: ../../tutorial/example/gmachine/gmachine-1.md:342 msgid "" "fn update(self : GState, n : Int) -> Unit {\n" " let addr = self.pop1()\n" -" let dst = @immut/list.unsafe_nth(self.stack, n)\n" +" let dst = self.stack.unsafe_nth(n)\n" " self.heap[dst] = NInd(addr)\n" "}\n" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:512 +#: ../../tutorial/example/gmachine/gmachine-1.md:348 msgid "" "The `Unwind` instruction in the G-Machine is akin to an evaluation loop. " "It has several branching conditions based on the type of node " "corresponding to the address at the top of the stack:" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:514 +#: ../../tutorial/example/gmachine/gmachine-1.md:350 msgid "For `Nnum` nodes: Do nothing." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:515 +#: ../../tutorial/example/gmachine/gmachine-1.md:351 msgid "" "For `NApp` nodes: Push the address of the left node onto the stack and " "`Unwind` again." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:516 +#: ../../tutorial/example/gmachine/gmachine-1.md:352 msgid "" "For `NGlobal` nodes: If there are enough parameters on the stack, load " "this super combinator into the current code." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:517 +#: ../../tutorial/example/gmachine/gmachine-1.md:353 msgid "" "For `NInd` nodes: Push the address contained within this indirect node " "onto the stack and Unwind again." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:519 +#: ../../tutorial/example/gmachine/gmachine-1.md:355 msgid "" "fn unwind(self : GState) -> Unit {\n" " let addr = self.pop1()\n" " match self.heap[addr] {\n" -" NNum(_) => self.putStack(addr)\n" +" NNum(_) => self.put_stack(addr)\n" " NApp(a1, _) => {\n" -" self.putStack(addr)\n" -" self.putStack(a1)\n" -" self.putCode(Cons(Unwind, Nil))\n" +" self.put_stack(addr)\n" +" self.put_stack(a1)\n" +" self.put_code(Cons(Unwind, Nil))\n" " }\n" -" NGlobal(_, n, c) => {\n" +" NGlobal(_, n, c) =>\n" " if self.stack.length() < n {\n" " abort(\"Unwinding with too few arguments\")\n" " } else {\n" -" self.putStack(addr)\n" -" self.putCode(c)\n" +" self.put_stack(addr)\n" +" self.put_code(c)\n" " }\n" -" }\n" " NInd(a) => {\n" -" self.putStack(a)\n" -" self.putCode(Cons(Unwind, Nil))\n" +" self.put_stack(a)\n" +" self.put_code(Cons(Unwind, Nil))\n" " }\n" -" otherwise => \n" -" abort(\"unwind() : wrong kind of node \\{otherwise}, address " -"\\{addr}\")\n" " }\n" "}\n" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:547 +#: ../../tutorial/example/gmachine/gmachine-1.md:361 msgid "" "The `Pop` instruction pops N addresses, eliminating the need for a " "separate function implementation." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:549 +#: ../../tutorial/example/gmachine/gmachine-1.md:363 msgid "Compiling Super Combinators into Instruction Sequences" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:551 +#: ../../tutorial/example/gmachine/gmachine-1.md:365 msgid "" "In the G-Machine Overview section, we roughly described the behavior of " "compiled super combinators. Now we can precisely describe the compilation" " process of super combinators." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:553 +#: ../../tutorial/example/gmachine/gmachine-1.md:367 msgid "" "Firstly, before the instruction sequence of a compiled super combinator " "is executed, there must be certain addresses already present in the " "stack:" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:555 +#: ../../tutorial/example/gmachine/gmachine-1.md:369 msgid "" "The topmost address points to an `NGlobal` node (the super combinator " "itself)." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:556 +#: ../../tutorial/example/gmachine/gmachine-1.md:370 msgid "" "Following are N addresses (N being the number of parameters for this " "super combinator), pointing to a series of App nodes - corresponding " @@ -1094,7 +1082,7 @@ msgid "" "suit." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:558 +#: ../../tutorial/example/gmachine/gmachine-1.md:372 msgid "" "When compiling a super combinator, we need to maintain an environment " "that allows us to find the relative position of parameters in the stack " @@ -1104,14 +1092,14 @@ msgid "" "be passed as well." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:560 +#: ../../tutorial/example/gmachine/gmachine-1.md:374 msgid "" "Here, \"parameters\" refer to addresses pointing to App nodes on the " "heap, and the actual parameter addresses can be accessed through the " "pusharg instruction." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:562 +#: ../../tutorial/example/gmachine/gmachine-1.md:376 msgid "" "fn compileSC(self : ScDef[String]) -> (String, Int, List[Instruction]) {\n" " let name = self.name\n" @@ -1126,33 +1114,34 @@ msgid "" " Cons(s, ss) => Cons((s, i), gen_env(i + 1, ss))\n" " }\n" " }\n" +"\n" " let env = gen_env(0, self.args)\n" " (name, arity, compileR(body, env, arity))\n" "}\n" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:581 +#: ../../tutorial/example/gmachine/gmachine-1.md:382 msgid "" "The `compileR` function generates code for instantiating super " "combinators by calling the `compileC` function, and then appends three " "instructions:" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:583 +#: ../../tutorial/example/gmachine/gmachine-1.md:384 msgid "" "`Update(N)`: Updates the original redex in the heap to an `NInd` node, " "which then points to the newly instantiated super combinator." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:584 +#: ../../tutorial/example/gmachine/gmachine-1.md:385 msgid "`Pop(N)`: Clears the stack of redundant addresses." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:585 +#: ../../tutorial/example/gmachine/gmachine-1.md:386 msgid "`Unwind`: Searches for the next redex to start the next reduction." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:587 +#: ../../tutorial/example/gmachine/gmachine-1.md:388 msgid "" "fn compileR(\n" " self : RawExpr[String],\n" @@ -1160,18 +1149,14 @@ msgid "" " arity : Int\n" ") -> List[Instruction] {\n" " if arity == 0 {\n" -" // The Pop 0 instruction does nothing in practice, \n" -" // so it is not generated when the arity is 0.\n" -" compileC(self, env).concat(@immut/list.of([Update(arity), Unwind]))\n" +" compileC(self, env) + List::of([Update(arity), Unwind])\n" " } else {\n" -" compileC(self, env).concat(\n" -" @immut/list.of([Update(arity), Pop(arity), Unwind]),\n" -" )\n" +" compileC(self, env) + List::of([Update(arity), Pop(arity), Unwind])\n" " }\n" "}\n" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:605 +#: ../../tutorial/example/gmachine/gmachine-1.md:394 msgid "" "When compiling the definition of super combinators, a rather crude " "approach is used: if a variable is not a parameter, it is treated as " @@ -1184,7 +1169,7 @@ msgid "" "added." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:607 +#: ../../tutorial/example/gmachine/gmachine-1.md:396 msgid "" "fn compileC(\n" " self : RawExpr[String],\n" @@ -1192,90 +1177,87 @@ msgid "" ") -> List[Instruction] {\n" " match self {\n" " Var(s) =>\n" -" match lookupENV(env, s) {\n" -" None => @immut/list.of([PushGlobal(s)])\n" -" Some(n) => @immut/list.of([PushArg(n)])\n" +" match env.lookup(s) {\n" +" None => List::of([PushGlobal(s)])\n" +" Some(n) => List::of([PushArg(n)])\n" " }\n" -" Num(n) => @immut/list.of([PushInt(n)])\n" +" Num(n) => List::of([PushInt(n)])\n" " App(e1, e2) =>\n" -" compileC(e2, env)\n" -" .concat(compileC(e1, argOffset(1, env)))\n" -" .concat(@immut/list.of([MkApp]))\n" +" compileC(e2, env) + compileC(e1, argOffset(1, env)) + " +"List::of([MkApp])\n" " _ => abort(\"not support yet\")\n" " }\n" "}\n" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:628 +#: ../../tutorial/example/gmachine/gmachine-1.md:402 msgid "Running the G-Machine" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:630 +#: ../../tutorial/example/gmachine/gmachine-1.md:404 msgid "" "Once the super combinators are compiled, they need to be placed on the " "heap (along with adding their addresses to the global table). This can be" " done recursively." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:632 +#: ../../tutorial/example/gmachine/gmachine-1.md:406 msgid "" -"fn buildInitialHeap(scdefs : List[(String, Int, List[Instruction])]) -> " -"(GHeap, RHTable[String, Addr]) {\n" -" let heap = { objectCount : 0, memory : Array::make(10000, None) }\n" -" let globals = RHTable::new(50)\n" -" fn go(lst : List[(String, Int, List[Instruction])]) {\n" -" match lst {\n" -" Nil => ()\n" -" Cons((name, arity, instrs), rest) => {\n" -" let addr = heap.alloc(NGlobal(name, arity, instrs))\n" -" globals[name] = addr\n" -" go(rest)\n" -" }\n" +"fn build_initial_heap(\n" +" scdefs : List[(String, Int, List[Instruction])]\n" +") -> (GHeap, @hashmap.T[String, Addr]) {\n" +" let heap = { object_count: 0, memory: Array::make(10000, None) }\n" +" let globals = @hashmap.new(capacity=50)\n" +" loop scdefs {\n" +" Nil => ()\n" +" Cons((name, arity, instrs), rest) => {\n" +" let addr = heap.alloc(NGlobal(name, arity, instrs))\n" +" globals[name] = addr\n" +" continue rest\n" " }\n" " }\n" -" go(scdefs)\n" " return (heap, globals)\n" "}\n" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:651 +#: ../../tutorial/example/gmachine/gmachine-1.md:412 msgid "" "Define a function \"step\" that updates the state of the G-Machine by one" " step, returning false if the final state has been reached." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:653 +#: ../../tutorial/example/gmachine/gmachine-1.md:414 msgid "" "fn step(self : GState) -> Bool {\n" " match self.code {\n" " Nil => return false\n" " Cons(i, is) => {\n" " self.code = is\n" -" self.statInc()\n" +" self.stat_incr()\n" " match i {\n" " PushGlobal(f) => self.push_global(f)\n" " PushInt(n) => self.push_int(n)\n" " PushArg(n) => self.push_arg(n)\n" -" MkApp => self.mkapp()\n" +" MkApp => self.mk_apply()\n" " Unwind => self.unwind()\n" " Update(n) => self.update(n)\n" " Pop(n) => self.stack = self.stack.drop(n)\n" -" } // without the need for additional functions\n" +" }\n" " return true\n" " }\n" " }\n" "}\n" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:675 +#: ../../tutorial/example/gmachine/gmachine-1.md:420 msgid "" "Additionally, define a function \"reify\" that continuously executes the " "\"step\" function until the final state is reached." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:677 +#: ../../tutorial/example/gmachine/gmachine-1.md:422 msgid "" -"fn reify(self : GState) -> Unit {\n" +"fn reify(self : GState) -> Node {\n" " if self.step() {\n" " self.reify()\n" " } else {\n" @@ -1283,7 +1265,7 @@ msgid "" " match stack {\n" " Cons(addr, Nil) => {\n" " let res = self.heap[addr]\n" -" println(\"\\{res}\")\n" +" return res\n" " }\n" " _ => abort(\"wrong stack \\{stack}\")\n" " }\n" @@ -1291,46 +1273,52 @@ msgid "" "}\n" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:694 +#: ../../tutorial/example/gmachine/gmachine-1.md:428 msgid "Combine the above components." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:696 +#: ../../tutorial/example/gmachine/gmachine-1.md:430 msgid "" -"fn run(codes : List[String]) -> Unit {\n" +"fn run(codes : List[String]) -> Node {\n" " fn parse_then_compile(code : String) -> (String, Int, " "List[Instruction]) {\n" -" let code = TokenStream::new(code)\n" -" let code = parseSC(code)\n" +" let tokens = tokenize(code)\n" +" let code = \n" +" try {\n" +" tokens.parse_sc!()\n" +" } catch {\n" +" ParseError(s) => abort(s)\n" +" } else {\n" +" expr => expr\n" +" }\n" " let code = compileSC(code)\n" " return code\n" " }\n" +" let codes = codes.map(parse_then_compile) + prelude_defs.map(compileSC)" "\n" -" let codes = " -"codes.map(parse_then_compile).concat(preludeDefs.map(compileSC))\n" -" let (heap, globals) = buildInitialHeap(codes)\n" +" let (heap, globals) = build_initial_heap(codes)\n" " let initialState : GState = {\n" -" heap,\n" -" stack: Nil,\n" -" code: initialCode,\n" -" globals,\n" -" stats: initialStat,\n" +" heap : heap,\n" +" stack : Nil,\n" +" code : List::of([PushGlobal(\"main\"), Unwind]),\n" +" globals : globals,\n" +" stats : 0\n" " }\n" " initialState.reify()\n" "}\n" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:718 -#: ../../tutorial/example/gmachine/gmachine-2.md:330 -#: ../../tutorial/example/myers-diff/myers-diff2.md:186 -#: ../../tutorial/example/myers-diff/myers-diff3.md:214 +#: ../../tutorial/example/gmachine/gmachine-1.md:436 +#: ../../tutorial/example/gmachine/gmachine-2.md:214 +#: ../../tutorial/example/myers-diff/myers-diff2.md:86 +#: ../../tutorial/example/myers-diff/myers-diff3.md:113 #: ../../tutorial/example/segment-tree/segment-tree.md:141 #: ../../tutorial/example/segment-tree/segment-tree2.md:132 #: ../../tutorial/example/sudoku/index.md:388 msgid "Conclusion" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:720 +#: ../../tutorial/example/gmachine/gmachine-1.md:438 msgid "" "The features of the G-Machine we've constructed so far are too limited to" " run even a somewhat decent program. In the next article, we will " @@ -1339,11 +1327,11 @@ msgid "" "covering the G-Machine." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:722 +#: ../../tutorial/example/gmachine/gmachine-1.md:440 msgid "Reference" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-1.md:724 +#: ../../tutorial/example/gmachine/gmachine-1.md:442 msgid "" "Peyton Jones, Simon & Lester, David. (2000). Implementing functional " "languages: a tutorial." @@ -1437,16 +1425,18 @@ msgstr "" #: ../../tutorial/example/gmachine/gmachine-2.md:39 msgid "" "fn rearrange(self : GState, n : Int) -> Unit {\n" -" let appnodes = take(self.stack, n)\n" -" let args = map(fn (addr) {\n" -" let NApp(_, arg) = self.heap[addr]\n" -" arg\n" -" }, appnodes)\n" -" self.stack = append(args, drop(appnodes, n - 1))\n" +" let appnodes = self.stack.take(n)\n" +" let args = appnodes.map(fn (addr) {\n" +" guard let NApp(_, arg) = self.heap[addr] else {\n" +" _ => panic()\n" +" }\n" +" arg \n" +" })\n" +" self.stack = args + appnodes.drop(n - 1)\n" "}\n" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-2.md:50 +#: ../../tutorial/example/gmachine/gmachine-2.md:45 msgid "" "The `rearrange` function assumes that the first N addresses on the stack " "point to a series of `NApp` nodes. It keeps the bottommost one (used as " @@ -1454,38 +1444,37 @@ msgid "" "addresses that directly point to the parameters." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-2.md:52 +#: ../../tutorial/example/gmachine/gmachine-2.md:47 msgid "" "After this, both parameters and local variables can be accessed using the" " same command by changing the `PushArg` instruction to a more general " "`Push` instruction." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-2.md:54 +#: ../../tutorial/example/gmachine/gmachine-2.md:49 msgid "" "fn push(self : GState, offset : Int) -> Unit {\n" -" // Copy the address at offset + 1 to the top of the stack\n" -" // Push(n) a0 : . . . : an : s\n" -" // => an : a0 : . . . : an : s\n" -" let appaddr = nth(self.stack, offset)\n" -" self.putStack(appaddr)\n" +" // Push(n) a0 : . . . : an : s\n" +" // => an : a0 : . . . : an : s\n" +" let addr = self.stack.unsafe_nth(offset)\n" +" self.put_stack(addr)\n" "}\n" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-2.md:64 +#: ../../tutorial/example/gmachine/gmachine-2.md:55 msgid "" "The next issue is that we need something to clean up. Consider the " "following expression:" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-2.md:66 +#: ../../tutorial/example/gmachine/gmachine-2.md:57 msgid "" "(let ([x1 e1]\n" " [x2 e2])\n" " expr)\n" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-2.md:72 +#: ../../tutorial/example/gmachine/gmachine-2.md:63 msgid "" "After constructing the graph corresponding to the expression `expr`, the " "stack still contains addresses pointing to e1 and e2 (corresponding to " @@ -1493,7 +1482,7 @@ msgid "" "top):" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-2.md:74 +#: ../../tutorial/example/gmachine/gmachine-2.md:65 msgid "" "
\n" " |\n" @@ -1504,7 +1493,7 @@ msgid "" "...remaining stack...\n" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-2.md:84 +#: ../../tutorial/example/gmachine/gmachine-2.md:75 msgid "" "Therefore, we need a new instruction to clean up these no longer needed " "addresses. It is called `Slide`. As the name suggests, the function of " @@ -1512,15 +1501,15 @@ msgid "" "addresses." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-2.md:86 +#: ../../tutorial/example/gmachine/gmachine-2.md:77 msgid "" "fn slide(self : GState, n : Int) -> Unit {\n" " let addr = self.pop1()\n" -" self.stack = Cons(addr, drop(self.stack, n))\n" +" self.stack = Cons(addr, self.stack.drop(n))\n" "}\n" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-2.md:93 +#: ../../tutorial/example/gmachine/gmachine-2.md:83 msgid "" "Now we can compile `let`. We will compile the expressions corresponding " "to local variables using the `compileC` function. Then, traverse the list" @@ -1530,32 +1519,33 @@ msgid "" "addresses." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-2.md:95 +#: ../../tutorial/example/gmachine/gmachine-2.md:85 msgid "" "Compiling the main expression using the passed function makes it easy to " "reuse when adding subsequent features." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-2.md:97 +#: ../../tutorial/example/gmachine/gmachine-2.md:87 msgid "" -"fn compileLet(comp : (RawExpr[String], List[(String, Int)]) -> " -"List[Instruction], defs : List[(String, RawExpr[String])], expr : " -"RawExpr[String], env : List[(String, Int)]) -> List[Instruction] {\n" +"fn compileLet(\n" +" comp : (RawExpr[String], List[(String, Int)]) -> List[Instruction],\n" +" defs : List[(String, RawExpr[String])],\n" +" expr : RawExpr[String],\n" +" env : List[(String, Int)]\n" +") -> List[Instruction] {\n" " let (env, codes) = loop env, List::Nil, defs {\n" " env, acc, Nil => (env, acc)\n" " env, acc, Cons((name, expr), rest) => {\n" " let code = compileC(expr, env)\n" -" // Update offsets and add offsets for local variables corresponding" -" to name\n" " let env = List::Cons((name, 0), argOffset(1, env))\n" -" continue env, append(acc, code), rest\n" +" continue env, acc + code, rest\n" " }\n" " }\n" -" append(codes, append(comp(expr, env), List::[Slide(length(defs))]))\n" +" codes + comp(expr, env) + List::of([Slide(defs.length())])\n" "}\n" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-2.md:112 +#: ../../tutorial/example/gmachine/gmachine-2.md:93 msgid "" "The semantics of `letrec` are more complex - it allows the N variables " "within the expression to reference each other, so we need to pre-allocate" @@ -1565,77 +1555,85 @@ msgid "" "negative and only serve as placeholders." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-2.md:114 +#: ../../tutorial/example/gmachine/gmachine-2.md:95 msgid "" -"fn allocNodes(self : GState, n : Int) -> Unit {\n" +"fn alloc_nodes(self : GState, n : Int) -> Unit {\n" " let dummynode : Node = NInd(Addr(-1))\n" " for i = 0; i < n; i = i + 1 {\n" " let addr = self.heap.alloc(dummynode)\n" -" self.putStack(addr)\n" +" self.put_stack(addr)\n" " }\n" "}\n" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-2.md:124 +#: ../../tutorial/example/gmachine/gmachine-2.md:101 msgid "The steps to compile letrec are similar to `let`:" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-2.md:126 +#: ../../tutorial/example/gmachine/gmachine-2.md:103 msgid "Use `Alloc(n)` to allocate N addresses." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-2.md:127 +#: ../../tutorial/example/gmachine/gmachine-2.md:104 msgid "Use the `loop` expression to build a complete environment." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-2.md:128 +#: ../../tutorial/example/gmachine/gmachine-2.md:105 msgid "" "Compile the local variables in `defs`, using the `Update` instruction to " "update the results to the pre-allocated addresses after compiling each " "one." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-2.md:129 +#: ../../tutorial/example/gmachine/gmachine-2.md:106 msgid "Compile the main expression and use the `Slide` instruction to clean up." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-2.md:131 +#: ../../tutorial/example/gmachine/gmachine-2.md:108 msgid "" -"fn compileLetrec(comp : (RawExpr[String], List[(String, Int)]) -> " -"List[Instruction], defs : List[(String, RawExpr[String])], expr : " -"RawExpr[String], env : List[(String, Int)]) -> List[Instruction] {\n" -" let env = loop env, defs {\n" -" env, Nil => env\n" -" env, Cons((name, _), rest) => {\n" -" let env = List::Cons((name, 0), argOffset(1, env))\n" -" continue env, rest\n" +"fn compileLetrec(\n" +" comp : (RawExpr[String], List[(String, Int)]) -> List[Instruction],\n" +" defs : List[(String, RawExpr[String])],\n" +" expr : RawExpr[String],\n" +" env : List[(String, Int)]\n" +") -> List[Instruction] {\n" +" let mut env = env\n" +" loop defs {\n" +" Nil => ()\n" +" Cons((name, _), rest) => {\n" +" env = Cons((name, 0), argOffset(1, env))\n" +" continue rest\n" " }\n" " }\n" -" let n = length(defs)\n" -" fn compileDefs(defs : List[(String, RawExpr[String])], offset : Int) ->" -" List[Instruction] {\n" +" let n = defs.length()\n" +" fn compileDefs(\n" +" defs : List[(String, RawExpr[String])],\n" +" offset : Int\n" +" ) -> List[Instruction] {\n" " match defs {\n" -" Nil => append(comp(expr, env), List::[Slide(n)])\n" -" Cons((_, expr), rest) => append(compileC(expr, env), " -"Cons(Update(offset), compileDefs(rest, offset - 1)))\n" +" Nil => comp(expr, env) + List::of([Slide(n)])\n" +" Cons((_, expr), rest) =>\n" +" compileC(expr, env) +\n" +" Cons(Update(offset), compileDefs(rest, offset - 1))\n" " }\n" " }\n" +"\n" " Cons(Alloc(n), compileDefs(defs, n - 1))\n" "}\n" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-2.md:151 +#: ../../tutorial/example/gmachine/gmachine-2.md:114 msgid "Adding Primitives" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-2.md:153 +#: ../../tutorial/example/gmachine/gmachine-2.md:116 msgid "" "From this step, we can finally perform basic integer operations such as " "arithmetic, comparison, and checking if two numbers are equal. First, " "modify the `Instruction` type to add related instructions." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-2.md:155 +#: ../../tutorial/example/gmachine/gmachine-2.md:118 msgid "" " Add\n" " Sub\n" @@ -1651,7 +1649,7 @@ msgid "" " Cond(List[Instruction], List[Instruction])\n" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-2.md:170 +#: ../../tutorial/example/gmachine/gmachine-2.md:133 msgid "" "At first glance, implementing these instructions seems simple. Take `Add`" " as an example: just pop two top addresses from the stack, retrieve the " @@ -1659,7 +1657,7 @@ msgid "" "result address back onto the stack." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-2.md:172 +#: ../../tutorial/example/gmachine/gmachine-2.md:135 msgid "" "fn add(self : GState) -> Unit {\n" " let (a1, a2) = self.pop2() // Pop two top addresses\n" @@ -1674,7 +1672,7 @@ msgid "" "}\n" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-2.md:186 +#: ../../tutorial/example/gmachine/gmachine-2.md:149 msgid "" "However, the next problem we face is that this is a lazy evaluation " "language. The parameters of `add` are likely not yet computed (i.e., not " @@ -1683,88 +1681,106 @@ msgid "" "Evaluation)." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-2.md:188 +#: ../../tutorial/example/gmachine/gmachine-2.md:151 msgid "" "In jargon, the result of such a computation is called Weak Head Normal " "Form (WHNF)." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-2.md:190 +#: ../../tutorial/example/gmachine/gmachine-2.md:153 msgid "" "At the same time, we need to modify the structure of `GState` and add a " "state called `dump`. Its type is `List[(List[Instruction], List[Addr])]`," " used by `Eval` and `Unwind` instructions." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-2.md:192 +#: ../../tutorial/example/gmachine/gmachine-2.md:155 msgid "The implementation of the `Eval` instruction is not complicated:" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-2.md:194 +#: ../../tutorial/example/gmachine/gmachine-2.md:157 msgid "Pop the top address of the stack." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-2.md:196 +#: ../../tutorial/example/gmachine/gmachine-2.md:159 msgid "" "Save the current unexecuted instruction sequence and stack (by putting " "them into the dump)." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-2.md:198 +#: ../../tutorial/example/gmachine/gmachine-2.md:161 msgid "Clear the current stack and place the previously saved address." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-2.md:200 +#: ../../tutorial/example/gmachine/gmachine-2.md:163 msgid "Clear the current instruction sequence and place the `Unwind` instruction." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-2.md:202 +#: ../../tutorial/example/gmachine/gmachine-2.md:165 msgid "" "This is similar to how strict evaluation languages handle saving caller " "contexts, but practical implementations would use more efficient methods." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-2.md:204 +#: ../../tutorial/example/gmachine/gmachine-2.md:167 msgid "" "fn eval(self : GState) -> Unit {\n" " let addr = self.pop1()\n" -" self.putDump(self.code, self.stack)\n" -" self.stack = List::[addr]\n" -" self.code = List::[Unwind]\n" +" self.put_dump(self.code, self.stack)\n" +" self.stack = List::of([addr])\n" +" self.code = List::of([Unwind])\n" "}\n" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-2.md:213 +#: ../../tutorial/example/gmachine/gmachine-2.md:173 msgid "" "This simple definition requires modifying the `Unwind` instruction to " "restore the context when `Unwind` in the `NNum` branch finds that there " "is a recoverable context (`dump` is not empty)." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-2.md:215 +#: ../../tutorial/example/gmachine/gmachine-2.md:175 msgid "" "fn unwind(self : GState) -> Unit {\n" " let addr = self.pop1()\n" " match self.heap[addr] {\n" " NNum(_) => {\n" " match self.dump {\n" -" Nil => self.putStack(addr)\n" -" Cons((instrs, stack), restDump) => {\n" -" // Restore the stack\n" +" Nil => self.put_stack(addr)\n" +" Cons((instrs, stack), rest_dump) => {\n" " self.stack = stack\n" -" self.putStack(addr)\n" -" self.dump = restDump\n" -" // Return to original code execution\n" +" self.put_stack(addr)\n" +" self.dump = rest_dump\n" " self.code = instrs\n" " }\n" " }\n" " }\n" -" ......\n" +" NApp(a1, _) => {\n" +" self.put_stack(addr)\n" +" self.put_stack(a1)\n" +" self.put_code(List::of([Unwind]))\n" +" }\n" +" NGlobal(_, n, c) => {\n" +" if self.stack.length() < n {\n" +" abort(\"Unwinding with too few arguments\")\n" +" } else {\n" +" if n != 0 {\n" +" self.rearrange(n)\n" +" } else {\n" +" self.put_stack(addr)\n" +" }\n" +" self.put_code(c)\n" +" }\n" +" }\n" +" NInd(a) => {\n" +" self.put_stack(a)\n" +" self.put_code(List::of([Unwind]))\n" +" }\n" " }\n" "}\n" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-2.md:237 +#: ../../tutorial/example/gmachine/gmachine-2.md:181 msgid "" "Next, we need to implement arithmetic and comparison instructions. We use" " two functions to simplify the form of binary operations. The result of " @@ -1772,127 +1788,177 @@ msgid "" " numbers to represent it: 0 for `false`, 1 for `true`." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-2.md:239 +#: ../../tutorial/example/gmachine/gmachine-2.md:183 msgid "" -"fn liftArith2(self : GState, op : (Int, Int) -> Int) -> Unit {\n" -" // Binary arithmetic operations\n" +"fn negate(self : GState) -> Unit {\n" +" let addr = self.pop1()\n" +" match self.heap[addr] {\n" +" NNum(n) => {\n" +" let addr = self.heap.alloc(NNum(-n))\n" +" self.put_stack(addr)\n" +" }\n" +" otherwise => {\n" +" abort(\"negate: wrong kind of node \\{otherwise}, address " +"\\{addr}\")\n" +" }\n" +" }\n" +"}\n" +"\n" +"fn lift_arith2(self : GState, op : (Int, Int) -> Int) -> Unit {\n" " let (a1, a2) = self.pop2()\n" " match (self.heap[a1], self.heap[a2]) {\n" " (NNum(n1), NNum(n2)) => {\n" " let newnode = Node::NNum(op(n1, n2))\n" " let addr = self.heap.alloc(newnode)\n" -" self.putStack(addr)\n" +" self.put_stack(addr)\n" " }\n" " (node1, node2) => abort(\"liftArith2: \\{a1} = \\{node1} \\{a2} = " "\\{node2}\")\n" " }\n" "}\n" "\n" -"fn liftCmp2(self : GState, op : (Int, Int) -> Bool) -> Unit {\n" -" // Binary comparison operations\n" +"fn lift_cmp2(self : GState, op : (Int, Int) -> Bool) -> Unit {\n" " let (a1, a2) = self.pop2()\n" " match (self.heap[a1], self.heap[a2]) {\n" " (NNum(n1), NNum(n2)) => {\n" " let flag = op(n1, n2)\n" " let newnode = if flag { Node::NNum(1) } else { Node::NNum(0) }\n" " let addr = self.heap.alloc(newnode)\n" -" self.putStack(addr)\n" +" self.put_stack(addr)\n" " }\n" " (node1, node2) => abort(\"liftCmp2: \\{a1} = \\{node1} \\{a2} = " "\\{node2}\")\n" " }\n" "}\n" -"\n" -"// Implement negation separately\n" -"fn negate(self : GState) -> Unit {\n" -" let addr = self.pop1()\n" -" match self.heap[addr] {\n" -" NNum(n) => {\n" -" let addr = self.heap.alloc(NNum(-n))\n" -" self.putStack(addr)\n" -" }\n" -" otherwise => {\n" -" // If not NNum, throw an error\n" -" abort(\"negate: wrong kind of node \\{otherwise}, address \\{addr} " -"\")\n" -" }\n" -" }\n" -"}\n" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-2.md:283 +#: ../../tutorial/example/gmachine/gmachine-2.md:189 msgid "Finally, implement branching:" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-2.md:285 +#: ../../tutorial/example/gmachine/gmachine-2.md:191 msgid "" "fn condition(self : GState, i1 : List[Instruction], i2 : " "List[Instruction]) -> Unit {\n" " let addr = self.pop1()\n" " match self.heap[addr] {\n" " NNum(0) => {\n" -" // If false, jump to i2\n" -" self.code = append(i2, self.code)\n" +" // false\n" +" self.code = i2 + self.code\n" " }\n" " NNum(1) => {\n" -" // If true, jump to i1\n" -" self.code = append(i1, self.code)\n" +" // true\n" +" self.code = i1 + self.code\n" " }\n" " otherwise => abort(\"cond : \\{addr} = \\{otherwise}\")\n" " }\n" "}\n" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-2.md:302 +#: ../../tutorial/example/gmachine/gmachine-2.md:197 msgid "" "No major adjustments are needed in the compilation part, just add some " "predefined programs:" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-2.md:304 +#: ../../tutorial/example/gmachine/gmachine-2.md:199 #: ../../tutorial/example/gmachine/gmachine-3.md:9 msgid "" -"let compiledPrimitives : List[(String, Int, List[Instruction])] = List::[" -"\n" -" // Arithmetic\n" -" (\"add\", 2, List::[Push(1), Eval, Push(1), Eval, Add, Update(2), " -"Pop(2), Unwind]),\n" -" (\"sub\", 2, List::[Push(1), Eval, Push(1), Eval, Sub, Update(2), " -"Pop(2), Unwind]),\n" -" (\"mul\", 2, List::[Push(1), Eval, Push(1), Eval, Mul, Update(2), " -"Pop(2), Unwind]),\n" -" (\"div\", 2, List::[Push(1), Eval, Push(1), Eval, Div, Update(2), " -"Pop(2), Unwind]),\n" -" // Comparison\n" -" (\"eq\", 2, List::[Push(1), Eval, Push(1), Eval, Eq, Update(2), " -"Pop(2), Unwind]),\n" -" (\"neq\", 2, List::[Push(1), Eval, Push(1), Eval, Ne, Update(2), " -"Pop(2), Unwind]),\n" -" (\"ge\", 2, List::[Push(1), Eval, Push(1), Eval, Ge, Update(2), " -"Pop(2), Unwind]),\n" -" (\"gt\", 2, List::[Push(1), Eval, Push(1), Eval, Gt, Update(2), " -"Pop(2), Unwind]),\n" -" (\"le\", 2, List::[Push(1), Eval, Push(1), Eval, Le, Update(2), " -"Pop(2), Unwind]),\n" -" (\"lt\", 2, List::[Push(1), Eval, Push(1), Eval, Lt, Update(2), " -"Pop(2), Unwind]),\n" -" // Miscellaneous\n" -" (\"negate\", 1, List::[Push(0), Eval, Neg, Update(1), Pop(1), Unwind])," -"\n" -" (\"if\", 3, List::[Push(0), Eval, Cond(List::[Push(1)], " -"List::[Push(2)]), Update(3), Pop(3), Unwind])\n" -"]\n" +"let compiled_primitives : List[(String, Int, List[Instruction])] = " +"List::of(\n" +" [\n" +" // Arith\n" +" (\n" +" \"add\",\n" +" 2,\n" +" List::of([Push(1), Eval, Push(1), Eval, Add, Update(2), Pop(2), " +"Unwind]),\n" +" ),\n" +" (\n" +" \"sub\",\n" +" 2,\n" +" List::of([Push(1), Eval, Push(1), Eval, Sub, Update(2), Pop(2), " +"Unwind]),\n" +" ),\n" +" (\n" +" \"mul\",\n" +" 2,\n" +" List::of([Push(1), Eval, Push(1), Eval, Mul, Update(2), Pop(2), " +"Unwind]),\n" +" ),\n" +" (\n" +" \"div\",\n" +" 2,\n" +" List::of([Push(1), Eval, Push(1), Eval, Div, Update(2), Pop(2), " +"Unwind]),\n" +" ),\n" +" // Compare\n" +" (\n" +" \"eq\",\n" +" 2,\n" +" List::of([Push(1), Eval, Push(1), Eval, Eq, Update(2), Pop(2), " +"Unwind]),\n" +" ),\n" +" (\n" +" \"neq\",\n" +" 2,\n" +" List::of([Push(1), Eval, Push(1), Eval, Ne, Update(2), Pop(2), " +"Unwind]),\n" +" ),\n" +" (\n" +" \"ge\",\n" +" 2,\n" +" List::of([Push(1), Eval, Push(1), Eval, Ge, Update(2), Pop(2), " +"Unwind]),\n" +" ),\n" +" (\n" +" \"gt\",\n" +" 2,\n" +" List::of([Push(1), Eval, Push(1), Eval, Gt, Update(2), Pop(2), " +"Unwind]),\n" +" ),\n" +" (\n" +" \"le\",\n" +" 2,\n" +" List::of([Push(1), Eval, Push(1), Eval, Le, Update(2), Pop(2), " +"Unwind]),\n" +" ),\n" +" (\n" +" \"lt\",\n" +" 2,\n" +" List::of([Push(1), Eval, Push(1), Eval, Lt, Update(2), Pop(2), " +"Unwind]),\n" +" ),\n" +" // MISC\n" +" (\"negate\", 1, List::of([Push(0), Eval, Neg, Update(1), Pop(1), " +"Unwind])),\n" +" (\n" +" \"if\",\n" +" 3,\n" +" List::of(\n" +" [\n" +" Push(0),\n" +" Eval,\n" +" Cond(List::of([Push(1)]), List::of([Push(2)])),\n" +" Update(3),\n" +" Pop(3),\n" +" Unwind,\n" +" ],\n" +" ),\n" +" ),\n" +" ],\n" +")\n" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-2.md:324 +#: ../../tutorial/example/gmachine/gmachine-2.md:205 msgid "and modify the initial instruction sequence" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-2.md:326 -msgid "let initialCode : List[Instruction] = List::[PushGlobal(\"main\"), Eval]\n" +#: ../../tutorial/example/gmachine/gmachine-2.md:207 +msgid "code : List::of([PushGlobal(\"main\"), Eval]),\n" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-2.md:332 +#: ../../tutorial/example/gmachine/gmachine-2.md:216 msgid "" "In the next part, we will improve the code generation for primitives and " "add support for data structures." @@ -1918,27 +1984,27 @@ msgstr "" #: ../../tutorial/example/gmachine/gmachine-3.md:7 msgid "" "Let's review how we implemented primitives in the [last " -"tutorial](https://www.moonbitlang.com/docs/examples/gmachine-2)." +"tutorial](gmachine-2.md)." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:29 +#: ../../tutorial/example/gmachine/gmachine-3.md:15 msgid "" "This implementation introduces many `Eval` instructions, but they are not" " always necessary. For example:" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:31 +#: ../../tutorial/example/gmachine/gmachine-3.md:17 msgid "(add 3 (mul 4 5))\n" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:35 +#: ../../tutorial/example/gmachine/gmachine-3.md:21 msgid "" "The two arguments of `add` are already in WHNF (Weak Head Normal Form) " "before executing `Eval`. Therefore, the `Eval` instructions here are " "redundant." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:37 +#: ../../tutorial/example/gmachine/gmachine-3.md:23 msgid "" "One feasible optimization method is to consider the context when " "compiling expressions. For example, `add` requires its arguments to be " @@ -1947,49 +2013,49 @@ msgid "" "safely compiled with strict evaluation (only a subset)." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:39 +#: ../../tutorial/example/gmachine/gmachine-3.md:25 msgid "An expression in a supercombinator definition is in a strict context." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:41 +#: ../../tutorial/example/gmachine/gmachine-3.md:27 msgid "" "If `(op e1 e2)` is in a strict context (where `op` is a primitive), then " "`e1` and `e2` are also in a strict context." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:43 +#: ../../tutorial/example/gmachine/gmachine-3.md:29 msgid "" "If `(let (.....) e)` is in a strict context, then `e` is also in a strict" " context (but the expressions corresponding to the local variables are " "not, as `e` may not need their results)." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:45 +#: ../../tutorial/example/gmachine/gmachine-3.md:31 msgid "" "We use the `compileE` function to implement compilation in a strict " "context, ensuring that _the value at the top of the stack is always in " "WHNF_." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:47 +#: ../../tutorial/example/gmachine/gmachine-3.md:33 msgid "" "For the default branch, we simply add an `Eval` instruction after the " "result of `compileC`." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:49 -msgid "append(compileC(self, env), List::[Eval])\n" +#: ../../tutorial/example/gmachine/gmachine-3.md:35 +msgid "_ => compileC(self, env) + List::of([Eval])\n" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:53 +#: ../../tutorial/example/gmachine/gmachine-3.md:42 msgid "Constants are pushed directly." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:55 -msgid "Num(n) => List::[PushInt(n)]\n" +#: ../../tutorial/example/gmachine/gmachine-3.md:44 +msgid "Num(n) => List::of([PushInt(n)])\n" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:59 +#: ../../tutorial/example/gmachine/gmachine-3.md:51 msgid "" "For `let/letrec` expressions, the specially designed `compileLet` and " "`compileLetrec` become useful. Compiling a `let/letrec` expression in a " @@ -1997,7 +2063,7 @@ msgid "" "expression." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:61 +#: ../../tutorial/example/gmachine/gmachine-3.md:53 msgid "" "Let(rec, defs, e) => {\n" " if rec {\n" @@ -2008,43 +2074,43 @@ msgid "" "}\n" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:71 +#: ../../tutorial/example/gmachine/gmachine-3.md:60 msgid "" "The `if` and `negate` functions, with 3 and 1 arguments respectively, " "require special handling." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:73 +#: ../../tutorial/example/gmachine/gmachine-3.md:62 msgid "" "App(App(App(Var(\"if\"), b), e1), e2) => {\n" " let condition = compileE(b, env)\n" " let branch1 = compileE(e1, env)\n" " let branch2 = compileE(e2, env)\n" -" append(condition, List::[Cond(branch1, branch2)])\n" +" condition + List::of([Cond(branch1, branch2)])\n" "}\n" "App(Var(\"negate\"), e) => {\n" -" append(compileE(e, env), List::[Neg])\n" +" compileE(e, env) + List::of([Neg])\n" "}\n" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:85 +#: ../../tutorial/example/gmachine/gmachine-3.md:69 msgid "" "Basic binary operations can be handled uniformly through a lookup table. " "First, construct a hash table called `builtinOpS` to query the " "corresponding instructions by the name of the primitive." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:87 +#: ../../tutorial/example/gmachine/gmachine-3.md:71 msgid "" -"let builtinOpS : RHTable[String, Instruction] = {\n" -" let table : RHTable[String, Instruction] = RHTable::new(50)\n" -" table[\"add\"] = Add\n" +"let builtinOpS : @hashmap.T[String, Instruction] = {\n" +" let table = @hashmap.new(capacity = 50)\n" +" table[\"add\"] = Add \n" " table[\"mul\"] = Mul\n" " table[\"sub\"] = Sub\n" " table[\"div\"] = Div\n" " table[\"eq\"] = Eq\n" " table[\"neq\"] = Ne\n" -" table[\"ge\"] = Ge\n" +" table[\"ge\"] = Ge \n" " table[\"gt\"] = Gt\n" " table[\"le\"] = Le\n" " table[\"lt\"] = Lt\n" @@ -2052,46 +2118,45 @@ msgid "" "}\n" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:104 +#: ../../tutorial/example/gmachine/gmachine-3.md:77 msgid "The rest of the handling is not much different." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:106 +#: ../../tutorial/example/gmachine/gmachine-3.md:79 msgid "" "App(App(Var(op), e0), e1) => {\n" " match builtinOpS[op] {\n" -" None => append(compileC(self, env), List::[Eval]) // Not a primitive " -"op, use the default branch\n" +" None => compileC(self, env) + List::of([Eval])\n" " Some(instr) => {\n" " let code1 = compileE(e1, env)\n" " let code0 = compileE(e0, argOffset(1, env))\n" -" append(code1, append(code0, List::[instr]))\n" +" code1 + code0 + List::of([instr])\n" " }\n" " }\n" "}\n" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:119 +#: ../../tutorial/example/gmachine/gmachine-3.md:86 msgid "" "Are we done? It seems so, but there's another WHNF besides integers: " "partially applied functions." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:121 +#: ../../tutorial/example/gmachine/gmachine-3.md:88 msgid "" "A partial application is when the number of arguments is insufficient. " "This situation is common in higher-order functions, for example:" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:123 +#: ../../tutorial/example/gmachine/gmachine-3.md:90 msgid "(map (add 1) listofnumbers)\n" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:127 +#: ../../tutorial/example/gmachine/gmachine-3.md:94 msgid "Here, `(add 1)` is a partial application." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:129 +#: ../../tutorial/example/gmachine/gmachine-3.md:96 msgid "" "To ensure that the code generated by the new compilation strategy works " "correctly, we need to modify the implementation of the `Unwind` " @@ -2100,10 +2165,10 @@ msgid "" "original redex and restore the stack." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:131 +#: ../../tutorial/example/gmachine/gmachine-3.md:98 msgid "" "NGlobal(_, n, c) => {\n" -" let k = length(self.stack)\n" +" let k = self.stack.length()\n" " if k < n {\n" " match self.dump {\n" " Nil => abort(\"Unwinding with too few arguments\")\n" @@ -2111,19 +2176,23 @@ msgid "" " // a1 : ...... : ak\n" " // ||\n" " // ak : s\n" -" // Retain the redex and restore the stack\n" -" self.stack = append(drop(self.stack, k - 1), s)\n" +" self.stack = self.stack.drop(k - 1) + s\n" " self.dump = rest\n" " self.code = i\n" " }\n" " }\n" " } else {\n" -" ......\n" +" if n != 0 {\n" +" self.rearrange(n)\n" +" } else {\n" +" self.put_stack(addr)\n" +" }\n" +" self.put_code(c)\n" " }\n" "}\n" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:153 +#: ../../tutorial/example/gmachine/gmachine-3.md:105 msgid "" "This context-based strictness analysis technique is useful but cannot do " "anything with supercombinator calls. Here we briefly introduce a " @@ -2132,7 +2201,7 @@ msgid "" "using strict mode." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:155 +#: ../../tutorial/example/gmachine/gmachine-3.md:107 msgid "" "We first define a concept: bottom, which conceptually represents a value " "that never terminates or causes an exception. For a supercombinator `f " @@ -2143,7 +2212,7 @@ msgid "" "result. Therefore, a`[i]` should be strictly evaluated." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:157 +#: ../../tutorial/example/gmachine/gmachine-3.md:109 msgid "" "If this condition is not met, it does not necessarily mean that the " "argument is not needed at all; it may be used only in certain branches " @@ -2151,24 +2220,24 @@ msgid "" "example of one that should be lazily evaluated." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:159 +#: ../../tutorial/example/gmachine/gmachine-3.md:111 msgid "" "Let's consider bottom as `false` and non-bottom values as `true`. In this" " way, all functions in coref can be considered boolean functions. Take " "`abs` as an example:" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:161 +#: ../../tutorial/example/gmachine/gmachine-3.md:113 msgid "" "(defn abs[n]\n" " (if (lt n 0) (negate n) n))\n" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:166 +#: ../../tutorial/example/gmachine/gmachine-3.md:118 msgid "We analyze how to translate it into a boolean function from top to bottom:" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:168 +#: ../../tutorial/example/gmachine/gmachine-3.md:120 msgid "" "For an expression like `(if x y z)`, x must be evaluated, but only one of" " `y` or `z` needs to be evaluated. This can be translated into `x and (y " @@ -2177,11 +2246,11 @@ msgid "" "entire expression is also bottom." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:170 +#: ../../tutorial/example/gmachine/gmachine-3.md:122 msgid "For primitive expressions, using `and` for all parts is sufficient." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:172 +#: ../../tutorial/example/gmachine/gmachine-3.md:124 msgid "" "To determine whether a parameter needs to be compiled strictly, you can " "convert the above condition into a Boolean function: `a[i] = false` " @@ -2189,17 +2258,17 @@ msgid "" "being true)." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:174 +#: ../../tutorial/example/gmachine/gmachine-3.md:126 msgid "" "This is essentially a method of program analysis called \"abstract " "interpretation.\"" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:176 +#: ../../tutorial/example/gmachine/gmachine-3.md:128 msgid "Custom Data Structures" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:178 +#: ../../tutorial/example/gmachine/gmachine-3.md:130 msgid "" "The data structure type definition in Haskell is similar to the `enum` in" " MoonBit. However, since CoreF is a simple toy language used to " @@ -2207,7 +2276,7 @@ msgid "" "only built-in data structure is the lazy list." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:180 +#: ../../tutorial/example/gmachine/gmachine-3.md:132 msgid "" "(defn take[n l]\n" " (case l\n" @@ -2218,82 +2287,82 @@ msgid "" " (Cons x (take (sub n 1) xs)))]))\n" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:190 +#: ../../tutorial/example/gmachine/gmachine-3.md:142 msgid "" "As shown above, you can use the `case` expression for simple pattern " "matching on lists." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:192 +#: ../../tutorial/example/gmachine/gmachine-3.md:144 msgid "" "The corresponding graph node for a list is `NConstr(Int, List[Addr])`, " "which consists of two parts:" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:194 +#: ../../tutorial/example/gmachine/gmachine-3.md:146 msgid "" "A tag for different value constructors: the tag for `Nil` is 0, and the " "tag for `Cons` is 1." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:195 +#: ../../tutorial/example/gmachine/gmachine-3.md:147 msgid "" "A list of addresses for storing substructures, whose length corresponds " "to the number of parameters (arity) of a value constructor." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:197 +#: ../../tutorial/example/gmachine/gmachine-3.md:149 msgid "" "This graph node structure can be used to implement various data " "structures, but CoreF does not have a type system. For demonstration " "purposes, only lazy lists are implemented." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:199 +#: ../../tutorial/example/gmachine/gmachine-3.md:151 msgid "" "We need to add two instructions, `Split` and `Pack`, to deconstruct and " "construct lists." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:201 +#: ../../tutorial/example/gmachine/gmachine-3.md:153 msgid "" -"fn split(self : GState, n : Int) -> Unit {\n" +"fn pack(self : GState, t : Int, n : Int) -> Unit {\n" +" let addrs = self.stack.take(n)\n" +" self.stack = self.stack.drop(n)\n" +" let addr = self.heap.alloc(NConstr(t, addrs))\n" +" self.put_stack(addr)\n" +"}\n" +"\n" +"fn split(self : GState) -> Unit {\n" " let addr = self.pop1()\n" " match self.heap[addr] {\n" " NConstr(_, addrs) => {\n" " // n == addrs.length()\n" " self.stack = addrs + self.stack\n" " }\n" +" _ => panic()\n" " }\n" "}\n" -"\n" -"fn pack(self : GState, t : Int, n : Int) -> Unit {\n" -" let addrs = self.stack.take(n)\n" -" // Assume the number of arguments is sufficient\n" -" self.stack = self.stack.drop(n)\n" -" let addr = self.heap.alloc(NConstr(t, addrs))\n" -" self.putStack(addr)\n" -"}\n" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:221 +#: ../../tutorial/example/gmachine/gmachine-3.md:160 msgid "" "Additionally, a `CaseJump` instruction is needed to implement the `case` " "expression." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:223 +#: ../../tutorial/example/gmachine/gmachine-3.md:162 msgid "" "fn casejump(self : GState, table : List[(Int, List[Instruction])]) -> " "Unit {\n" " let addr = self.pop1()\n" " match self.heap[addr] {\n" -" NConstr(t, addrs) => {\n" -" match lookupENV(table, t) {\n" +" NConstr(t, _) => {\n" +" match table.lookup(t) {\n" " None => abort(\"casejump\")\n" -" Some(instrs) => {\n" +" Some(instrs) => { \n" " self.code = instrs + self.code\n" -" self.putStack(addr)\n" +" self.put_stack(addr)\n" " }\n" " }\n" " }\n" @@ -2303,7 +2372,7 @@ msgid "" "}\n" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:241 +#: ../../tutorial/example/gmachine/gmachine-3.md:168 msgid "" "After adding the above instructions, we need to modify the `compileC` and" " `compileE` functions. Since the object matched by the `case` expression " @@ -2311,35 +2380,34 @@ msgid "" "it." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:243 +#: ../../tutorial/example/gmachine/gmachine-3.md:170 msgid "" -"// compileE\n" -" Case(e, alts) => {\n" -" compileE(e, env) + List::[CaseJump(compileAlts(alts, env))]\n" -" }\n" -" Constructor(0, 0) => {\n" -" // Nil\n" -" List::[Pack(0, 0)]\n" -" }\n" -" App(App(Constructor(1, 2), x), xs) => {\n" -" // Cons(x, xs)\n" -" compileC(xs, env) + compileC(x, argOffset(1, env)) + List::[Pack(1, " -"2)]\n" -" }\n" -"\n" -"// compileC\n" -" App(App(Constructor(1, 2), x), xs) => {\n" -" // Cons(x, xs)\n" -" compileC(xs, env) + compileC(x, argOffset(1, env)) + List::[Pack(1, " -"2)]\n" -" }\n" -" Constructor(0, 0) => {\n" -" // Nil\n" -" List::[Pack(0, 0)]\n" -" }\n" +"App(App(Constructor(tag = 1, arity = 2), x), xs) => {\n" +" // Cons(x, xs)\n" +" compileC(xs, env) + compileC(x, argOffset(1, env)) + List::of([Pack(1, " +"2)])\n" +"}\n" +"// Nil\n" +"Constructor(tag = 0, arity = 0) => List::of([Pack(0, 0)])\n" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:268 +#: ../../tutorial/example/gmachine/gmachine-3.md:177 +msgid "" +"Case(e, alts) => {\n" +" compileE(e, env) + List::of([CaseJump(compileAlts(alts, env))])\n" +"}\n" +"Constructor(tag = 0, arity = 0) => {\n" +" // Nil\n" +" List::of([Pack(0, 0)])\n" +"}\n" +"App(App(Constructor(tag = 1, arity = 2), x), xs) => {\n" +" // Cons(x, xs)\n" +" compileC(xs, env) + compileC(x, argOffset(1, env)) + List::of([Pack(1, " +"2)])\n" +"}\n" +msgstr "" + +#: ../../tutorial/example/gmachine/gmachine-3.md:184 msgid "" "At this point, a new problem arises. Previously, printing the evaluation " "result only needed to handle simple `NNum` nodes, but `NConstr` nodes " @@ -2349,13 +2417,8 @@ msgid "" " into the `output` component of `GState`." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:270 +#: ../../tutorial/example/gmachine/gmachine-3.md:186 msgid "" -"struct GState {\n" -" output : Buffer\n" -" ......\n" -"}\n" -"\n" "fn gprint(self : GState) -> Unit {\n" " let addr = self.pop1()\n" " match self.heap[addr] {\n" @@ -2365,62 +2428,59 @@ msgid "" " }\n" " NConstr(0, Nil) => self.output.write_string(\"Nil\")\n" " NConstr(1, Cons(addr1, Cons(addr2, Nil))) => {\n" -" // Force evaluation of addr1 and addr2 is required, so we execute " -"Eval instructions first\n" -" self.code = List::[Instruction::Eval, Print, Eval, Print] + " +" self.code = List::of([Instruction::Eval, Print, Eval, Print]) + " "self.code\n" -" self.putStack(addr2)\n" -" self.putStack(addr1)\n" +" self.put_stack(addr2)\n" +" self.put_stack(addr1)\n" " }\n" +" _ => panic()\n" " }\n" "}\n" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:294 +#: ../../tutorial/example/gmachine/gmachine-3.md:192 msgid "Finally, change the initial code of the G-Machine to:" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:296 -msgid "" -"let initialCode : List[Instruction] = List::[PushGlobal(\"main\"), Eval, " -"Print]\n" +#: ../../tutorial/example/gmachine/gmachine-3.md:194 +msgid "code : List::of([PushGlobal(\"main\"), Eval, Print]),\n" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:300 +#: ../../tutorial/example/gmachine/gmachine-3.md:201 msgid "" "Now, we can write some classic functional programs using lazy lists, such" " as the infinite Fibonacci sequence:" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:302 +#: ../../tutorial/example/gmachine/gmachine-3.md:203 msgid "(defn fibs[] (Cons 0 (Cons 1 (zipWith add fibs (tail fibs)))))\n" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:306 +#: ../../tutorial/example/gmachine/gmachine-3.md:207 msgid "" "After introducing data structures, strictness analysis becomes more " "complex. For lazy lists, there are various evaluation modes:" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:308 +#: ../../tutorial/example/gmachine/gmachine-3.md:209 msgid "" "Fully strict (requires the list to be finite and all elements to be non-" "bottom)." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:309 +#: ../../tutorial/example/gmachine/gmachine-3.md:210 msgid "Fully lazy." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:310 +#: ../../tutorial/example/gmachine/gmachine-3.md:211 msgid "Head strict (the list can be infinite, but its elements cannot be bottom)." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:311 +#: ../../tutorial/example/gmachine/gmachine-3.md:212 msgid "Tail strict (the list must be finite, but its elements can be bottom)." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:313 +#: ../../tutorial/example/gmachine/gmachine-3.md:214 msgid "" "Moreover, the context in which a function is used can change the " "evaluation mode of its parameters (it cannot be analyzed in isolation and" @@ -2429,45 +2489,45 @@ msgid "" "includes:" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:315 +#: ../../tutorial/example/gmachine/gmachine-3.md:216 msgid "Projections for Strictness Analysis" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:317 +#: ../../tutorial/example/gmachine/gmachine-3.md:218 msgid "Static Analysis and Code Optimizations in Glasgow Haskell Compiler" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:319 +#: ../../tutorial/example/gmachine/gmachine-3.md:220 msgid "Implementing Projection-based Strictness Analysis" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:321 +#: ../../tutorial/example/gmachine/gmachine-3.md:222 msgid "Theory and Practice of Demand Analysis in Haskell" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:323 -#: ../../tutorial/example/myers-diff/myers-diff.md:382 +#: ../../tutorial/example/gmachine/gmachine-3.md:224 +#: ../../tutorial/example/myers-diff/myers-diff.md:311 msgid "Epilogue" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:325 +#: ../../tutorial/example/gmachine/gmachine-3.md:226 msgid "" "Lazy evaluation can reduce runtime redundant calculations, but it also " "introduces new problems, such as:" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:327 +#: ../../tutorial/example/gmachine/gmachine-3.md:228 msgid "The notorious side effect order issue." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:329 +#: ../../tutorial/example/gmachine/gmachine-3.md:230 msgid "" "Excessive redundant nodes. Some computations that are not shared still " "store their results on the heap, which is detrimental to utilizing the " "CPU's caching mechanism." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:331 +#: ../../tutorial/example/gmachine/gmachine-3.md:232 msgid "" "The representative of lazy evaluation languages, Haskell, offers a " "controversial solution to the side effect order problem: Monads. This " @@ -2476,21 +2536,21 @@ msgid "" " to explain how to use it effectively." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:333 +#: ../../tutorial/example/gmachine/gmachine-3.md:234 msgid "" "Idris2, Haskell's successor (which is no longer a lazy language), retains" " Monads and introduces another mechanism for handling side effects: " "Algebraic Effects." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:335 +#: ../../tutorial/example/gmachine/gmachine-3.md:236 msgid "" "The Spineless G-Machine designed by SPJ improved the problem of excessive" " redundant nodes, and its successor, the STG, unified the data layout of " "different types of nodes." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:337 +#: ../../tutorial/example/gmachine/gmachine-3.md:238 msgid "" "In addition to improvements in abstract machine models, GHC's " "optimization of Haskell programs heavily relies on inline-based " @@ -2498,7 +2558,7 @@ msgid "" "techniques." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:339 +#: ../../tutorial/example/gmachine/gmachine-3.md:240 msgid "" "In 2004, several GHC designers discovered that the previous push-enter " "model, where parameters are pushed onto the stack and then a function is " @@ -2508,7 +2568,7 @@ msgid "" "Languages.\"" msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:341 +#: ../../tutorial/example/gmachine/gmachine-3.md:242 msgid "" "In 2007, Simon Marlow found that jump and execute code in the tagless " "design significantly affected the performance of modern CPU branch " @@ -2516,19 +2576,38 @@ msgid "" " described several solutions." msgstr "" -#: ../../tutorial/example/gmachine/gmachine-3.md:343 +#: ../../tutorial/example/gmachine/gmachine-3.md:244 msgid "" "Lazy purely functional languages have shown many interesting " "possibilities, but they have also faced much criticism and reflection. " "Nevertheless, it is undoubtedly an intriguing technology!" msgstr "" -#: ../../tutorial/example/gmachine/index.md:3 ../../tutorial/example/index.md:5 +#: ../../tutorial/example/gmachine/index.md:7 ../../tutorial/example/index.md:5 #: ../../tutorial/example/myers-diff/index.md:3 -#: ../../tutorial/example/segment-tree/index.md:13 ../../tutorial/index.md:8 +#: ../../tutorial/example/segment-tree/index.md:13 msgid "Contents:" msgstr "目录:" +#: ../../tutorial/example/gmachine/index.md:3 +msgid "" +"Lazy evaluation stands as a foundational concept in the realm of " +"programming languages. Haskell, renowned as a purely functional " +"programming language, boasts a robust lazy evaluation mechanism. This " +"mechanism not only empowers developers to craft code that's both more " +"efficient and concise but also enhances program performance and " +"responsiveness, especially when tackling sizable datasets or intricate " +"data streams." +msgstr "" + +#: ../../tutorial/example/gmachine/index.md:5 +msgid "" +"In this article, we'll delve into the Lazy Evaluation mechanism, " +"thoroughly examining its principles and implementation methods, and then " +"explore how to implement Haskell's evaluation semantics in " +"[MoonBit](https://www.moonbitlang.com/)." +msgstr "" + #: ../../tutorial/example/index.md:1 msgid "Examples" msgstr "" @@ -3416,64 +3495,63 @@ msgstr "" #: ../../tutorial/example/myers-diff/myers-diff.md:210 msgid "" +"///|\n" "struct Line {\n" " number : Int // Line number\n" " text : String // Does not include newline\n" -"} derive(Debug, Show)\n" +"} derive(Show)\n" "\n" +"///|\n" "fn Line::new(number : Int, text : String) -> Line {\n" -" Line::{ number : number, text : text }\n" +" Line::{ number, text }\n" "}\n" msgstr "" -#: ../../tutorial/example/myers-diff/myers-diff.md:221 +#: ../../tutorial/example/myers-diff/myers-diff.md:216 msgid "" "Then, define a helper function that splits a string into `Array[Line]` " "based on newline characters. Note that line numbers start from 1." msgstr "" -#: ../../tutorial/example/myers-diff/myers-diff.md:223 +#: ../../tutorial/example/myers-diff/myers-diff.md:218 msgid "" "fn lines(str : String) -> Array[Line] {\n" +" let lines = Array::new(capacity=50)\n" " let mut line_number = 0\n" -" let buf = Buffer::make(50)\n" -" let vec = []\n" -" for i = 0; i < str.length(); i = i + 1 {\n" -" let ch = str[i]\n" -" buf.write_char(ch)\n" -" if ch == '\\n' {\n" -" let text = buf.to_string()\n" -" buf.reset()\n" -" line_number = line_number + 1\n" -" vec.push(Line::new(line_number, text))\n" -" }\n" +" for line in str.split(\"\\n\") {\n" +" line_number = line_number + 1\n" +" lines.push(Line::new(line_number, line))\n" " } else {\n" -" // The text may not end with a newline\n" -" let text = buf.to_string()\n" -" if text != \"\" {\n" -" line_number = line_number + 1\n" -" vec.push(Line::new(line_number, text))\n" -" }\n" -" vec\n" +" return lines\n" " }\n" "}\n" msgstr "" -#: ../../tutorial/example/myers-diff/myers-diff.md:249 +#: ../../tutorial/example/myers-diff/myers-diff.md:224 msgid "" "Next, we need to wrap the array so that it supports negative indexing " "because we will use the value of `k` as an index." msgstr "" -#: ../../tutorial/example/myers-diff/myers-diff.md:251 +#: ../../tutorial/example/myers-diff/myers-diff.md:226 msgid "" -"type BPArray[T] Array[T] // BiPolar Array\n" +"type BPArray[T] Array[T] // BiPolar Array \n" "\n" "fn BPArray::make[T](capacity : Int, default : T) -> BPArray[T] {\n" " let arr = Array::make(capacity, default)\n" " BPArray(arr)\n" "}\n" "\n" +"fn copy(self : BPArray[Int]) -> BPArray[Int] {\n" +" let BPArray(arr) = self\n" +" let newarr = Array::make(arr.length(), 0)\n" +" for i = 0; i < arr.length(); i = i + 1 {\n" +" newarr[i] = arr[i]\n" +" } else {\n" +" BPArray(newarr)\n" +" }\n" +"}\n" +"\n" "fn op_get[T](self : BPArray[T], idx : Int) -> T {\n" " let BPArray(arr) = self\n" " if idx < 0 {\n" @@ -3493,18 +3571,18 @@ msgid "" "}\n" msgstr "" -#: ../../tutorial/example/myers-diff/myers-diff.md:278 +#: ../../tutorial/example/myers-diff/myers-diff.md:232 msgid "" "Now we can start writing the search function. Before searching for the " "complete path, let's start with our first goal to find the length of the " "shortest path (equal to the search depth). Here is the basic framework:" msgstr "" -#: ../../tutorial/example/myers-diff/myers-diff.md:280 +#: ../../tutorial/example/myers-diff/myers-diff.md:235 msgid "" -"fn shortst_edit(a : Array[Line], b : Array[Line]) -> Int {\n" -" let n = a.length()\n" -" let m = b.length()\n" +"fn shortst_edit(old~ : Array[Line], new~ : Array[Line]) -> Int {\n" +" let n = old.length()\n" +" let m = new.length()\n" " let max = n + m\n" " let v = BPArray::make(2 * max + 1, 0)\n" " for d = 0; d < max + 1; d = d + 1 {\n" @@ -3515,7 +3593,7 @@ msgid "" "}\n" msgstr "" -#: ../../tutorial/example/myers-diff/myers-diff.md:294 +#: ../../tutorial/example/myers-diff/myers-diff.md:249 msgid "" "In the most extreme case (the two texts have no matching lines), it can " "be inferred that the maximum number of steps needed is `n + m`, and the " @@ -3525,7 +3603,7 @@ msgid "" "1`." msgstr "" -#: ../../tutorial/example/myers-diff/myers-diff.md:296 +#: ../../tutorial/example/myers-diff/myers-diff.md:251 msgid "" "But even at this point, it is still difficult to figure out what to do " "next, so let's only consider the case `d = 0; k = 0` for now. At this " @@ -3534,12 +3612,12 @@ msgid "" "coordinates of this round into the array `v`." msgstr "" -#: ../../tutorial/example/myers-diff/myers-diff.md:298 +#: ../../tutorial/example/myers-diff/myers-diff.md:254 msgid "" "if d == 0 { // When d equals 0, k must also equal 0\n" " x = 0\n" " y = x - k\n" -" while x < n && y < m && a[x].text == b[y].text {\n" +" while x < n && y < m && old[x].text == new[y].text {\n" " // Skip all matching lines\n" " x = x + 1\n" " y = y + 1\n" @@ -3548,7 +3626,7 @@ msgid "" "}\n" msgstr "" -#: ../../tutorial/example/myers-diff/myers-diff.md:311 +#: ../../tutorial/example/myers-diff/myers-diff.md:267 msgid "" "When `d > 0`, the coordinate information stored from the previous round " "is required. When we know the `k` value of a point and the coordinates of" @@ -3559,26 +3637,26 @@ msgid "" "ending at `v[k - 1]` and `v[k + 1]`?" msgstr "" -#: ../../tutorial/example/myers-diff/myers-diff.md:313 +#: ../../tutorial/example/myers-diff/myers-diff.md:269 msgid "There are two boundary cases: `k == -d` and `k == d`." msgstr "" -#: ../../tutorial/example/myers-diff/myers-diff.md:315 +#: ../../tutorial/example/myers-diff/myers-diff.md:271 msgid "When `k == -d`, you can only choose `v[k + 1]`." msgstr "" -#: ../../tutorial/example/myers-diff/myers-diff.md:317 +#: ../../tutorial/example/myers-diff/myers-diff.md:273 msgid "When `k == -d`, you can only choose `v[k - 1]`." msgstr "" -#: ../../tutorial/example/myers-diff/myers-diff.md:319 +#: ../../tutorial/example/myers-diff/myers-diff.md:275 msgid "" "Recalling the requirement mentioned earlier: arranging deletions before " "insertions as much as possible, this essentially means choosing the " "position with the largest `x` value from the previous position." msgstr "" -#: ../../tutorial/example/myers-diff/myers-diff.md:321 +#: ../../tutorial/example/myers-diff/myers-diff.md:278 msgid "" "if k == -d {\n" " x = v[k + 1]\n" @@ -3591,11 +3669,11 @@ msgid "" "}\n" msgstr "" -#: ../../tutorial/example/myers-diff/myers-diff.md:333 +#: ../../tutorial/example/myers-diff/myers-diff.md:290 msgid "Merging these four branches, we get the following code:" msgstr "" -#: ../../tutorial/example/myers-diff/myers-diff.md:335 +#: ../../tutorial/example/myers-diff/myers-diff.md:293 msgid "" "if k == -d || (k != d && v[k - 1] < v[k + 1]) {\n" " x = v[k + 1]\n" @@ -3604,15 +3682,15 @@ msgid "" "}\n" msgstr "" -#: ../../tutorial/example/myers-diff/myers-diff.md:343 +#: ../../tutorial/example/myers-diff/myers-diff.md:301 msgid "Combining all the steps above, we get the following code:" msgstr "" -#: ../../tutorial/example/myers-diff/myers-diff.md:345 +#: ../../tutorial/example/myers-diff/myers-diff.md:303 msgid "" -"fn shortst_edit(a : Array[Line], b : Array[Line]) -> Int {\n" -" let n = a.length()\n" -" let m = b.length()\n" +"fn shortest_edit(old~ : Array[Line], new~ : Array[Line]) -> Int {\n" +" let n = old.length()\n" +" let m = new.length()\n" " let max = n + m\n" " let v = BPArray::make(2 * max + 1, 0)\n" " // v[1] = 0\n" @@ -3629,7 +3707,8 @@ msgid "" " x = v[k - 1] + 1\n" " }\n" " y = x - k\n" -" while x < n && y < m && a[x].text == b[y].text {\n" +" while x < n && y < m && old[x].text == new[y].text {\n" +" // Skip all matching lines\n" " x = x + 1\n" " y = y + 1\n" " }\n" @@ -3644,13 +3723,13 @@ msgid "" "}\n" msgstr "" -#: ../../tutorial/example/myers-diff/myers-diff.md:380 +#: ../../tutorial/example/myers-diff/myers-diff.md:309 msgid "" "Since the initial value of the array is 0, we can omit the branch for `d " "== 0`." msgstr "" -#: ../../tutorial/example/myers-diff/myers-diff.md:384 +#: ../../tutorial/example/myers-diff/myers-diff.md:313 msgid "" "We have implemented an incomplete version of Myers' algorithm, which " "completes the forward path search. In the next article, we will implement" @@ -3658,18 +3737,18 @@ msgid "" "to output a colored diff." msgstr "" -#: ../../tutorial/example/myers-diff/myers-diff.md:386 +#: ../../tutorial/example/myers-diff/myers-diff.md:315 msgid "This article references:" msgstr "" -#: ../../tutorial/example/myers-diff/myers-diff.md:388 +#: ../../tutorial/example/myers-diff/myers-diff.md:317 msgid "" "[https://blog.jcoglan.com/2017/02/15/the-myers-diff-algorithm-" "part-2/](https://blog.jcoglan.com/2017/02/15/the-myers-diff-algorithm-" "part-2/)" msgstr "" -#: ../../tutorial/example/myers-diff/myers-diff.md:390 +#: ../../tutorial/example/myers-diff/myers-diff.md:319 msgid "Thanks to the author James Coglan." msgstr "" @@ -3701,10 +3780,12 @@ msgstr "" #: ../../tutorial/example/myers-diff/myers-diff2.md:9 msgid "" -"fn shortest_edit(a : Array[Line], b : Array[Line]) -> " -"Array[(BPArray[Int], Int)] {\n" -" let n = a.length()\n" -" let m = b.length()\n" +"fn shortest_edit(\n" +" old~ : Array[Line],\n" +" new~ : Array[Line]\n" +") -> Array[(BPArray[Int], Int)] {\n" +" let n = old.length()\n" +" let m = new.length()\n" " let max = n + m\n" " let v = BPArray::make(2 * max + 1, 0)\n" " let trace = []\n" @@ -3713,7 +3794,7 @@ msgid "" " }\n" " // v[1] = 0\n" " for d = 0; d < max + 1; d = d + 1 {\n" -" push(v.copy(), d) // Save search depth and node\n" +" push(v.copy(), d) \n" " for k = -d; k < d + 1; k = k + 2 {\n" " let mut x = 0\n" " let mut y = 0\n" @@ -3726,11 +3807,10 @@ msgid "" " x = v[k - 1] + 1\n" " }\n" " y = x - k\n" -" while x < n && y < m && a[x].text == b[y].text {\n" +" while x < n && y < m && old[x].text == new[y].text {\n" " x = x + 1\n" " y = y + 1\n" " }\n" -"\n" " v[k] = x\n" " if x >= n && y >= m {\n" " return trace\n" @@ -3742,127 +3822,126 @@ msgid "" "}\n" msgstr "" -#: ../../tutorial/example/myers-diff/myers-diff2.md:50 +#: ../../tutorial/example/myers-diff/myers-diff2.md:15 msgid "Backtracking the Edit Path" msgstr "" -#: ../../tutorial/example/myers-diff/myers-diff2.md:52 +#: ../../tutorial/example/myers-diff/myers-diff2.md:17 msgid "" "After recording the entire search process, the next step is to walk back " "from the endpoint to find the path taken. But before we do that, let's " "first define the `Edit` type." msgstr "" -#: ../../tutorial/example/myers-diff/myers-diff2.md:54 +#: ../../tutorial/example/myers-diff/myers-diff2.md:19 msgid "" "enum Edit {\n" -" Insert(~new : Line)\n" -" Delete(~old : Line)\n" -" Equal(~old : Line, ~new : Line) // old, new\n" -"} derive(Debug, Show)\n" +" Insert(new~ : Line)\n" +" Delete(old~ : Line)\n" +" Equal(old~ : Line, new~ : Line) // old, new\n" +"} derive(Show)\n" msgstr "" -#: ../../tutorial/example/myers-diff/myers-diff2.md:62 +#: ../../tutorial/example/myers-diff/myers-diff2.md:25 msgid "Next, let's perform the backtracking." msgstr "" -#: ../../tutorial/example/myers-diff/myers-diff2.md:64 +#: ../../tutorial/example/myers-diff/myers-diff2.md:27 msgid "" -"fn backtrack(a : Array[Line], b : Array[Line], trace : " -"Array[(BPArray[Int], Int)]) -> Array[Edit] {\n" -" let mut x = a.length()\n" -" let mut y = b.length()\n" -" let edits = []\n" -" fn push(edit : Edit) -> Unit {\n" -" edits.push(edit)\n" -" }\n" -" ......\n" +"fn backtrack(\n" +" new~ : Array[Line],\n" +" old~ : Array[Line],\n" +" trace : Array[(BPArray[Int], Int)]\n" +") -> Array[Edit] {\n" +" let mut x = old.length()\n" +" let mut y = new.length()\n" +" let edits = Array::new(capacity=trace.length())\n" msgstr "" -#: ../../tutorial/example/myers-diff/myers-diff2.md:75 +#: ../../tutorial/example/myers-diff/myers-diff2.md:33 msgid "" "The method of backtracking is essentially the same as forward search, " "just in reverse." msgstr "" -#: ../../tutorial/example/myers-diff/myers-diff2.md:77 +#: ../../tutorial/example/myers-diff/myers-diff2.md:35 msgid "Calculate the current `k` value using `x` and `y`." msgstr "" -#: ../../tutorial/example/myers-diff/myers-diff2.md:79 +#: ../../tutorial/example/myers-diff/myers-diff2.md:37 msgid "" "Access the historical records and use the same judgment criteria as in " "forward search to find the `k` value at the previous search round." msgstr "" -#: ../../tutorial/example/myers-diff/myers-diff2.md:81 +#: ../../tutorial/example/myers-diff/myers-diff2.md:39 msgid "Restore the coordinates of the previous search round." msgstr "" -#: ../../tutorial/example/myers-diff/myers-diff2.md:83 +#: ../../tutorial/example/myers-diff/myers-diff2.md:41 msgid "Try free movement and record the corresponding edit actions." msgstr "" -#: ../../tutorial/example/myers-diff/myers-diff2.md:85 +#: ../../tutorial/example/myers-diff/myers-diff2.md:43 msgid "Determine the type of edit that caused the change in `k` value." msgstr "" -#: ../../tutorial/example/myers-diff/myers-diff2.md:87 +#: ../../tutorial/example/myers-diff/myers-diff2.md:45 msgid "Continue iterating." msgstr "" -#: ../../tutorial/example/myers-diff/myers-diff2.md:89 +#: ../../tutorial/example/myers-diff/myers-diff2.md:47 msgid "" -" for i = trace.length() - 1; i >= 0; i = i - 1 {\n" -" let (v, d) = trace[i]\n" -" let k = x - y\n" -" let prev_k = if k == -d || (k != d && v[k - 1] < v[k + 1]) {\n" -" k + 1\n" -" } else {\n" -" k - 1\n" -" }\n" -" let prev_x = v[prev_k]\n" -" let prev_y = prev_x - prev_k\n" -" while x > prev_x && y > prev_y {\n" -" x = x - 1\n" -" y = y - 1\n" -" push(Equal(old = a[x], new = b[y]))\n" -" }\n" -" if d > 0 {\n" -" if x == prev_x {\n" -" push(Insert(new = b[prev_y]))\n" -" } else if y == prev_y {\n" -" push(Delete(old = a[prev_x]))\n" -" }\n" -" x = prev_x\n" -" y = prev_y\n" +"for i = trace.length() - 1; i >= 0; i = i - 1 {\n" +" let (v, d) = trace[i]\n" +" let k = x - y\n" +" let prev_k = if k == -d || (k != d && v[k - 1] < v[k + 1]) {\n" +" k + 1\n" +" } else {\n" +" k - 1\n" +" }\n" +" let prev_x = v[prev_k]\n" +" let prev_y = prev_x - prev_k\n" +" while x > prev_x && y > prev_y {\n" +" x = x - 1\n" +" y = y - 1\n" +" edits.push(Equal(old=old[x], new=new[y]))\n" +" }\n" +" if d > 0 {\n" +" if x == prev_x {\n" +" edits.push(Insert(new=new[prev_y]))\n" +" } else if y == prev_y {\n" +" edits.push(Delete(old=old[prev_x]))\n" " }\n" +" x = prev_x\n" +" y = prev_y\n" " }\n" +"}\n" msgstr "" -#: ../../tutorial/example/myers-diff/myers-diff2.md:117 +#: ../../tutorial/example/myers-diff/myers-diff2.md:54 msgid "Combining the two functions, we get a complete `diff` implementation." msgstr "" -#: ../../tutorial/example/myers-diff/myers-diff2.md:119 +#: ../../tutorial/example/myers-diff/myers-diff2.md:56 msgid "" -"fn diff(a : Array[Line], b : Array[Line]) -> Array[Edit] {\n" -" let trace = shortest_edit(a, b)\n" -" backtrack(a, b, trace)\n" +"fn diff(old~ : Array[Line], new~ : Array[Line]) -> Array[Edit] {\n" +" let trace = shortest_edit(old~, new~)\n" +" backtrack(old~, new~, trace)\n" "}\n" msgstr "" -#: ../../tutorial/example/myers-diff/myers-diff2.md:126 +#: ../../tutorial/example/myers-diff/myers-diff2.md:62 msgid "Printing the Diff" msgstr "" -#: ../../tutorial/example/myers-diff/myers-diff2.md:128 +#: ../../tutorial/example/myers-diff/myers-diff2.md:64 msgid "" "To print a neat diff, we need to left-align the text. Also, due to the " "order issue during backtracking, we need to print from back to front." msgstr "" -#: ../../tutorial/example/myers-diff/myers-diff2.md:130 +#: ../../tutorial/example/myers-diff/myers-diff2.md:66 msgid "" "let line_width = 4\n" "\n" @@ -3870,7 +3949,7 @@ msgid "" " String::make(width - s.length(), ' ') + s\n" "}\n" "\n" -"fn print_edit(edit : Edit) -> String {\n" +"fn pprint_edit(edit : Edit) -> String {\n" " match edit {\n" " Insert(_) as edit => {\n" " let tag = \"+\"\n" @@ -3896,20 +3975,22 @@ msgid "" " }\n" "}\n" "\n" -"fn print_diff(diff : Array[Edit]) -> Unit {\n" -" for i = diff.length() - 1; i >= 0; i = i - 1 {\n" -" diff[i]\n" -" |> print_edit\n" -" |> println\n" +"fn pprint_diff(diff : Array[Edit]) -> String {\n" +" let buf = @buffer.new(size_hint = 100)\n" +" for i = diff.length(); i > 0; i = i - 1 {\n" +" buf.write_string(pprint_edit(diff[i - 1]))\n" +" buf.write_char('\\n')\n" +" } else {\n" +" buf.contents().to_unchecked_string()\n" " }\n" "}\n" msgstr "" -#: ../../tutorial/example/myers-diff/myers-diff2.md:172 +#: ../../tutorial/example/myers-diff/myers-diff2.md:72 msgid "The result is as follows:" msgstr "" -#: ../../tutorial/example/myers-diff/myers-diff2.md:174 +#: ../../tutorial/example/myers-diff/myers-diff2.md:74 msgid "" "- 1 A\n" "- 2 B\n" @@ -3922,7 +4003,7 @@ msgid "" "+ 6 C\n" msgstr "" -#: ../../tutorial/example/myers-diff/myers-diff2.md:188 +#: ../../tutorial/example/myers-diff/myers-diff2.md:88 msgid "" "The Myers algorithm demonstrated above is complete, but due to the " "frequent copying of arrays, it has a very large space overhead. " @@ -4072,16 +4153,16 @@ msgstr "" #: ../../tutorial/example/myers-diff/myers-diff3.md:74 msgid "" "struct Box {\n" -" left : Int,\n" -" right : Int,\n" -" top : Int,\n" +" left : Int\n" +" right : Int\n" +" top : Int\n" " bottom : Int\n" -"} derive(Debug, Show)\n" +"} derive(Show)\n" "\n" "struct Snake {\n" -" start : (Int, Int),\n" +" start : (Int, Int)\n" " end : (Int, Int)\n" -"} derive(Debug, Show)\n" +"} derive(Show)\n" "\n" "fn width(self : Box) -> Int {\n" " self.right - self.left\n" @@ -4100,7 +4181,7 @@ msgid "" "}\n" msgstr "" -#: ../../tutorial/example/myers-diff/myers-diff3.md:104 +#: ../../tutorial/example/myers-diff/myers-diff3.md:80 msgid "" "To avoid getting bogged down in details too early, let's assume we " "already have a function `midpoint : (Box, Array[Line], Array[Line]) -> " @@ -4108,164 +4189,198 @@ msgid "" "`find_path` to search for the complete path." msgstr "" -#: ../../tutorial/example/myers-diff/myers-diff3.md:106 -msgid "" -"fn find_path(box : Box, a : Array[Line], b : Array[Line]) -> Iter[(Int, " -"Int)]? {\n" -" let snake = midpoint(box, a, b)?;\n" -" let start = snake.start;\n" -" let end = snake.end;\n" -" let headbox = Box { left: box.left, top: box.top, right: start.0, " -"bottom: start.1 };\n" -" let tailbox = Box { left: end.0, top: end.1, right: box.right, bottom: " -"box.bottom };\n" -" // println(\"snake = \\{snake}\")\n" -" // println(\"headbox = \\{headbox}\")\n" -" // println(\"tailbox = \\{tailbox}\")\n" -" let head = find_path(headbox, a, b).or(Iter::singleton(start));\n" -" let tail = find_path(tailbox, a, b).or(Iter::singleton(end));\n" +#: ../../tutorial/example/myers-diff/myers-diff3.md:82 +msgid "" +"fn find_path(\n" +" box : Box,\n" +" old~ : Array[Line],\n" +" new~ : Array[Line]\n" +") -> Iter[(Int, Int)]? {\n" +" guard let Some(snake) = midpoint(box, old~, new~) else { None => None }" +"\n" +" let start = snake.start\n" +" let end = snake.end\n" +" let headbox = Box::{\n" +" left: box.left,\n" +" top: box.top,\n" +" right: start.0,\n" +" bottom: start.1,\n" +" }\n" +" let tailbox = Box::{\n" +" left: end.0,\n" +" top: end.1,\n" +" right: box.right,\n" +" bottom: box.bottom,\n" +" }\n" +" let head = find_path(headbox, old~, new~).or(Iter::singleton(start))\n" +" let tail = find_path(tailbox, old~, new~).or(Iter::singleton(end))\n" " Some(head.concat(tail))\n" "}\n" msgstr "" -#: ../../tutorial/example/myers-diff/myers-diff3.md:122 +#: ../../tutorial/example/myers-diff/myers-diff3.md:88 msgid "" "The implementation of `find_path` is straightforward, but `midpoint` is a" " bit more complex:" msgstr "" -#: ../../tutorial/example/myers-diff/myers-diff3.md:124 +#: ../../tutorial/example/myers-diff/myers-diff3.md:90 msgid "For a `Box` of size 0, return `None`." msgstr "" -#: ../../tutorial/example/myers-diff/myers-diff3.md:125 +#: ../../tutorial/example/myers-diff/myers-diff3.md:91 msgid "" "Calculate the search boundaries. Since forward and backward searches each" " cover half the distance, divide by two. However, if the size of the " "`Box` is odd, add one more to the forward search boundary." msgstr "" -#: ../../tutorial/example/myers-diff/myers-diff3.md:126 +#: ../../tutorial/example/myers-diff/myers-diff3.md:92 msgid "Store the results of the forward and backward searches in two arrays." msgstr "" -#: ../../tutorial/example/myers-diff/myers-diff3.md:127 +#: ../../tutorial/example/myers-diff/myers-diff3.md:93 msgid "" "Alternate between forward and backward searches, returning `None` if no " "result is found." msgstr "" -#: ../../tutorial/example/myers-diff/myers-diff3.md:129 +#: ../../tutorial/example/myers-diff/myers-diff3.md:95 msgid "" -"fn midpoint(self : Box, a : Array[Line], b : Array[Line]) -> Snake? {\n" +"fn midpoint(self : Box, old~ : Array[Line], new~ : Array[Line]) -> Snake?" +" {\n" " if self.size() == 0 {\n" -" return None;\n" +" return None\n" " }\n" " let max = {\n" -" let half = self.size() / 2;\n" +" let half = self.size() / 2\n" " if is_odd(self.size()) {\n" " half + 1\n" " } else {\n" " half\n" " }\n" -" };\n" -" let vf = BPArray::make(2 * max + 1, 0);\n" -" vf[1] = self.left;\n" -" let vb = BPArray::make(2 * max + 1, 0);\n" -" vb[1] = self.bottom;\n" -" for d in 0..max + 1 {\n" -" match forward(self, vf, vb, d, a, b) {\n" +" }\n" +" let vf = BPArray::make(2 * max + 1, 0)\n" +" vf[1] = self.left\n" +" let vb = BPArray::make(2 * max + 1, 0)\n" +" vb[1] = self.bottom\n" +" for d = 0; d < max + 1; d = d + 1 {\n" +" match self.forward(forward = vf, backward = vb, d, old~, new~) {\n" " None =>\n" -" match backward(self, vf, vb, d, a, b) {\n" -" None => continue,\n" -" res => return res,\n" -" },\n" -" res => return res,\n" +" match self.backward(forward = vf, backward = vb, d, old~, new~) {" +"\n" +" None => continue\n" +" res => return res\n" +" }\n" +" res => return res\n" " }\n" +" } else {\n" +" None\n" " }\n" -" None\n" "}\n" msgstr "" -#: ../../tutorial/example/myers-diff/myers-diff3.md:160 +#: ../../tutorial/example/myers-diff/myers-diff3.md:101 msgid "" "The forward and backward searches have some modifications compared to the" " original Myers algorithm, which need a bit of explanation:" msgstr "" -#: ../../tutorial/example/myers-diff/myers-diff3.md:162 +#: ../../tutorial/example/myers-diff/myers-diff3.md:103 msgid "" "Since we need to return the snake, the search process must calculate the " "previous coordinate (`px` stands for previous x)." msgstr "" -#: ../../tutorial/example/myers-diff/myers-diff3.md:163 +#: ../../tutorial/example/myers-diff/myers-diff3.md:104 msgid "" "The search now works within a `Box` (not the global edit graph), so " "calculating `y` from `x` (or vice versa) requires conversion." msgstr "" -#: ../../tutorial/example/myers-diff/myers-diff3.md:164 +#: ../../tutorial/example/myers-diff/myers-diff3.md:105 msgid "" "The backward search minimizes `y` as a heuristic strategy, but minimizing" " `x` would also work." msgstr "" -#: ../../tutorial/example/myers-diff/myers-diff3.md:166 -msgid "" -"fn forward(self : Box, vf : BPArray, vb : BPArray, d : Int, a :" -" Array[Line], b : Array[Line]) -> Snake? {\n" -" for k in (0..=d).rev() {\n" -" let c = k - self.delta();\n" -" let (mut x, mut px) = if k == -d || (k != d && vf[k - 1] < vf[k\n" -"\n" -" + 1]) {\n" -" (vf[k + 1], vf[k + 1])\n" +#: ../../tutorial/example/myers-diff/myers-diff3.md:107 +msgid "" +"fn forward(\n" +" self : Box,\n" +" forward~ : BPArray[Int],\n" +" backward~ : BPArray[Int],\n" +" depth : Int,\n" +" old~ : Array[Line],\n" +" new~ : Array[Line]\n" +") -> Snake? {\n" +" for k = depth; k >= -depth; k = k - 2 {\n" +" let c = k - self.delta()\n" +" let mut x = 0\n" +" let mut px = 0\n" +" if k == -depth || (k != depth && forward[k - 1] < forward[k + 1]) {\n" +" x = forward[k + 1]\n" +" px = x\n" " } else {\n" -" (vf[k - 1] + 1, vf[k - 1])\n" -" };\n" -" let mut y = self.top + (x - self.left) - k;\n" -" let py = if d == 0 || x != px { y } else { y - 1 };\n" -" while x < self.right && y < self.bottom && a[x].text == b[y].text {\n" -" x += 1;\n" -" y += 1;\n" +" px = forward[k - 1]\n" +" x = px + 1\n" +" }\n" +" let mut y = self.top + (x - self.left) - k\n" +" let py = if depth == 0 || x != px { y } else { y - 1 }\n" +" while x < self.right && y < self.bottom && old[x].text == new[y].text" +" {\n" +" x = x + 1\n" +" y = y + 1\n" " }\n" -" vf[k] = x;\n" -" if is_odd(self.delta()) && (c >= -(d - 1) && c <= d - 1) && y >= " -"vb[c] {\n" -" return Some(Snake { start: (px, py), end: (x, y) });\n" +" forward[k] = x\n" +" if is_odd(self.delta()) &&\n" +" (c >= -(depth - 1) && c <= depth - 1) &&\n" +" y >= backward[c] {\n" +" return Some(Snake::{ start: (px, py), end: (x, y) })\n" " }\n" " }\n" -" None\n" +" return None\n" "}\n" "\n" -"fn backward(self : Box, vf : BPArray, vb : BPArray, d : Int, a " -": Array[Line], b : Array[Line]) -> Snake? {\n" -" for c in (0..=d).rev() {\n" -" let k = c + self.delta();\n" -" let (mut y, mut py) = if c == -d || (c != d && vb[c - 1] > vb[c + 1])" -" {\n" -" (vb[c + 1], vb[c + 1])\n" +"\n" +"fn backward(\n" +" self : Box,\n" +" forward~ : BPArray[Int],\n" +" backward~ : BPArray[Int],\n" +" depth : Int,\n" +" old~ : Array[Line],\n" +" new~ : Array[Line]\n" +") -> Snake? {\n" +" for c = depth; c >= -depth; c = c - 2 {\n" +" let k = c + self.delta()\n" +" let mut y = 0\n" +" let mut py = 0\n" +" if c == -depth || (c != depth && backward[c - 1] > backward[c + 1]) {" +"\n" +" y = backward[c + 1]\n" +" py = y\n" " } else {\n" -" (vb[c - 1] - 1, vb[c - 1])\n" -" };\n" -" let mut x = self.left + (y - self.top) + k;\n" -" let px = if d == 0 || y != py { x } else { x + 1 };\n" -" while x > self.left && y > self.top && a[x - 1].text == b[y - 1].text" -" {\n" -" x -= 1;\n" -" y -= 1;\n" +" py = backward[c - 1]\n" +" y = py - 1\n" +" }\n" +" let mut x = self.left + (y - self.top) + k\n" +" let px = if depth == 0 || y != py { x } else { x + 1 }\n" +" while x > self.left && y > self.top && old[x - 1].text == new[y - " +"1].text {\n" +" x = x - 1\n" +" y = y - 1\n" " }\n" -" vb[c] = y;\n" -" if is_even(self.delta()) && (k >= -d && k <= d) && x <= vf[k] {\n" -" return Some(Snake { start: (x, y), end: (px, py) });\n" +" backward[c] = y\n" +" if is_even(self.delta()) && (k >= -depth && k <= depth) && x <= " +"forward[k] {\n" +" return Some(Snake::{ start: (x, y), end: (px, py) })\n" " }\n" " }\n" -" None\n" +" return None\n" "}\n" msgstr "" -#: ../../tutorial/example/myers-diff/myers-diff3.md:216 +#: ../../tutorial/example/myers-diff/myers-diff3.md:115 msgid "" "In addition to the default diff algorithm, Git also offers another diff " "algorithm called patience diff. It differs significantly from Myers diff " @@ -5802,10 +5917,14 @@ msgid "Here are some tutorials that may help you learn the programming language: msgstr "以下是一些可能帮助您学习编程语言的教程:" #: ../../tutorial/index.md:5 +msgid "[An interactive tour with language basics](https://tour.moonbitlang.com)" +msgstr "" + +#: ../../tutorial/index.md:6 msgid "[Tour for Beginners](./tour.md)" msgstr "[新手之旅](./tour.md)" -#: ../../tutorial/index.md:6 +#: ../../tutorial/index.md:7 msgid "[Examples](./example/index.md)" msgstr ""