Apply Jade's feedback

Signed-off-by: Danila Fedorin <daniel.fedorin@hpe.com>
This commit is contained in:
Danila Fedorin 2025-10-09 17:34:46 -07:00
parent 0c4129337a
commit 86f1ba686a

View File

@ -80,7 +80,7 @@ I can think of another language that has pure functions...
# Programming in Haskell
Without mutability and loops, Haskell programmers use pattern-matching and recursion to express their algorithms.
Without mutability and loops, (purely) functional programmers use pattern-matching and recursion to express their algorithms.
* Data structures are defined by enumerating their possible cases. A list is either empty, or a head element followed by a tail list.
@ -481,7 +481,7 @@ record _cons {
# Extracting Types from Format Strings
```Chapel
proc specifiers(param s: string, param i: int) type {
proc specifiers(param s: string, param i: int = 0) type {
if i >= s.size then return _nil;
if s[i] == "%" {
@ -509,7 +509,7 @@ proc specifiers(param s: string, param i: int) type {
Let's give it a quick try:
```Chapel
writeln(specifiers("Hello, %s! Your ChapelCon submission is #%i\n", 0) : string);
writeln(specifiers("Hello, %s! Your ChapelCon submission is #%i\n") : string);
```
The above prints:
@ -550,16 +550,16 @@ _cons(string,"a string",_cons(int(64),"a signed integer",_nil))
* To support the empty-specifier case (Chapel varargs don't allow zero arguments):
```Chapel
proc fprintln(param format: string) where specifiers(format, 0).length == 0 {
proc fprintln(param format: string) where specifiers(format).length == 0 {
writeln(format);
}
```
* If we do have type specifiers, to ensure our earlier assumption of `size` matching:
```Chapel
proc fprintln(param format: string, args...)
where specifiers(format, 0).length != args.size {
where specifiers(format).length != args.size {
compilerError("'fprintln' with this format string expects " +
specifiers(format, 0).length : string +
specifiers(format).length : string +
" argument(s) but got " + args.size : string);
}
```
@ -572,7 +572,7 @@ _cons(string,"a string",_cons(int(64),"a signed integer",_nil))
```Chapel
proc fprintln(param format: string, args...) {
validate(specifiers(format, 0), args.type, 0);
validate(specifiers(format), args.type, 0);
writef(format + "\n", (...args));
}
@ -707,7 +707,7 @@ For any two types, the _disjoint union_ of these two types defines values that a
* We can build up more complex types by combining these two operations.
* Need a triple of types $A$, $B$, and $C$? Use $A \times (B \times C)$.
* Similarly, "any one of three types" can be expressed as $A + (B + C)$.
* A `Result<T>` type (in Rust, or `optional<T>` in C++) is $T + \text{Unit}$.
* A `Option<T>` type (in Rust, or `optional<T>` in C++) is $T + \text{Unit}$.
* `Unit` is a type with a single value (there's only one `None` / `std::nullopt`).
* Notice that in Chapel, we moved up one level
@ -745,7 +745,7 @@ For any two types, the _disjoint union_ of these two types defines values that a
</div>
* So, we can't enforce that the user doesn't pass `int` to our `length` function defined on lists.
* We also can't enforce that `InL` is instantiated with the right type.
* So, we lose some safety compare to Haskell...
* So, we lose some safety compared to Haskell...
* ...but we're getting the compiler to do arbitrary computations for us at compile-time.
---