--- name: LB Stanza filename: learn-stanza.stanza contributors: - ["Mike Hilgendorf", "https://github.com/m-hilgendorf"] --- LB Stanza (or Stanza for short) is a new optionally-typed general purpose programming language from the University of California, Berkeley. Stanza was designed to help programmers tackle the complexity of architecting large programs and significantly increase the productivity of application programmers across the entire software development life cycle. ``` ; this is a comment ; This is a block comment ; block comments can be nested with optional tags. ; ; defpackage learn-stanza-in-y: import core import collections ;============================================================================== ; The basics, things you'd find in most programming languages ;============================================================================== ; Variables can be mutable (var) or immutable (val) val immutable = "this string can't be changed" var mutable = "this one can be" mutable = "like this" ; The basic data types (annotations are optional) val an-int: Int = 12345 val a-long: Long = 12345L val a-float: Float = 1.2345f val a-double: Double = 3.14159 val a-string: String = "this is a string" val a-multiline-string = \ this is a "raw" string literal \ ; Print a formatted string with println and "..." % [...] println("this is a formatted string %_ %_" % [mutable, immutable]) ; Stanza is optionally typed, and has a ? (any) type. var anything:? = 0 anything = 3.14159 anything = "a string" ; Stanza has basic collections like Tuples, Arrays, Vectors and HashTables val tuple: Tuple = [mutable, immutable] val array = Array(3) array[0] = "string" array[1] = 1 array[2] = 1.23455 ; array[3] = "out-of-bounds" ; arrays are bounds-checked val vector = Vector() vector[0] = "string" vector[1] = 1 vector[2] = 3.14159 val hash-table = HashTable() hash-table["0"] = 0 hash-table["1"] = 1 hash-table["2"] = 1 ;============================================================================== ; Functions ;============================================================================== ; Functions are declared with the `defn` keyword defn my-function (arg:?) : ; note the space between identifier and arg list println("called my-function with %_" % [arg]) my-function("arg") ; note the lack of a space to call the function ; Functions can be declared inside another function and capture variables from ; the surrounding environment. defn outer (arg): defn inner (): println("outer had arg: %_" % [arg]) inner() outer("something") ; functions are "first-class" in stanza, meaning you can assign variables ; to functions and pass functions as arguments to other functions. val a-function = outer defn do-n-times (arg, func, n:Int): for i in 0 to n do : func(arg) do-n-times("argument", a-function, 3) ; sometimes you want to define a function inline, or use an anonymous function. ; for this you can use the syntax: ; fn (args): ; ... do-n-times("hello", fn (arg): println(arg), 2) ; there is a shorthand for writing anonymous functions do-n-times("hello", { println(_) }, 2) ; the short hand works for multiple arguments as well. val multi-lambda = { println(_ + 2 * _) } multi-lambda(1, 2) ;============================================================================== ; User defined types ;============================================================================== ; Structs are declared with the `defstruct` keyword defstruct MyStruct: field ; constructors are derived automatically val my-struct = MyStruct("field:value") ; fields are accessed using function-call syntax println(field(my-struct)) ; Stanza supports subtyping with a "multimethod" system based on method ; overloading. deftype MyType defmulti a-method (m:MyType) defstruct Foo <: MyType defstruct Bar <: MyType defmethod a-method (a-foo: Foo): println("called a-method on a Foo") defmethod a-method (a-foo: Bar): println("called a-method on a Bar") ;============================================================================== ; The Type System ;============================================================================== ; True and Falseare types with a single value. val a-true: True = true val a-false: False = false ; You can declare a union type, or a value that is one of a set of types val a-boolean: True|False = true val another-boolean: True|False = false ; You can pattern match on types match(a-boolean): (t:True): println("is true") (f:False): println("is false") ; You can match against a single possible type match(a-boolean:True): println("is still true") else: println("is not true") ; You can compose program logic around the type of a variable if anything is Float : println("anything is a float") else if anything is-not String : println("anything is not an int") else : println("I don't know what anything is") ;============================================================================== ; Control Flow ;============================================================================== ; stanza has the standard basic control flow val condition = [false, false] if condition[0] : ; do something false else if condition[1] : ; do another thing false else : ; whatever else false ; there is also a switch statement, which can be used to pattern match ; on values (as opposed to types) switch(anything): "this": false "that": false "the-other-thing": false else: false ; for and while loops are supported while condition[0]: println("do stuff") for i in 0 to 10 do: vector[i] = i ; stanza also supports named labels which can function as break or return ; statements defn another-fn (): label return: label break: while true: if condition[0] is False: break(false) return(false) ; For a comprehensive guide on Stanza's advanced control flow, check out ; this page: http://lbstanza.org/chapter9.html from Stanza-by-Example ;============================================================================== ; Sequences ;============================================================================== ; for "loops" are sugar for a more powerful syntax. val xs = [1, 2, 3] val ys = ['a', 'b', 'c'] val zs = ["foo", "bar", "baz"] for (x in xs, y in ys, z in zs) do : println("x:%_, y:%_, z:%_" % [x, y, z]) ;xs, ys, and zs are all "Seqable" meaning they are Seq types (sequences). ; the `do` identifier is a special function that just applies the body of ; the for loop to each element of the sequence. ; ; A common sequence task is concatenating sequences. This is accomplished ; using the `seq-cat` function. This is analogous to "flattening" iterateors val concat = to-tuple $ for sequence in [xs, ys, zs] seq-cat: sequence ; we can also use a variation to interleave the elements of multiple sequences val interleaved = to-tuple $ for (x in xs, y in ys, z in zs) seq-cat : [x, y, z] println("[%,] [%,]" % [concat, interleaved]) ; Another common task is mapping a sequence to another, for example multiplying ; all the elements of a list of numbers by a constant. To do this we use `seq`. var numbers = [1.0, 2.0, 3.0, 4.0] numbers = to-tuple $ for n in numbers seq : 2.0 * n println("%," % [numbers]) if find({_ == 2.0}, numbers) is-not False : println("found it!") ; or maybe we just want to know if there's something in a sequence var is-there = for n in numbers any? : n == 2.0 ; since this is "syntactic sugar" we can write it explicitly using an ; anonymous function is-there = any?({_ == 2.0}, numbers) ; a detailed reference of the sequence library and various adaptors can ; be found here: http://lbstanza.org/reference.html#anchor439 ========================================================================= ; Documentation ;========================================================================= ; ; Top level statements can be prefixed with the "doc" field which takes ; a string value and is used to autogenerate documentation for the package. doc: \ # Document Strings ``` val you-can = "include code snippets, too" ``` To render documentation as markdown (compatible with mdbook) ```bash stanza doc source.stanza -o docs ``` \ defn docfn () : false ```