diff --git a/type-level/slides.md b/type-level/slides.md index f50d78c..5ed2ba4 100644 --- a/type-level/slides.md +++ b/type-level/slides.md @@ -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` type (in Rust, or `optional` in C++) is $T + \text{Unit}$. + * A `Option` type (in Rust, or `optional` 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 * 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. ---