Continuing to toss ideas around and work on different parts of the base design.
This commit is contained in:
parent
5854408466
commit
218647484d
11 changed files with 197 additions and 54 deletions
|
@ -5,19 +5,16 @@ _Constants_ are definitions which provide a name and explicit type for some
|
|||
constant.
|
||||
|
||||
```
|
||||
const weak_pi: Float64 is 3.14
|
||||
const my_name: String is "Pat"
|
||||
const weak_pi: Float64 := 3.14
|
||||
const my_name: String := "Pat"
|
||||
```
|
||||
|
||||
In general:
|
||||
|
||||
```
|
||||
const <name>: <type> is <value>
|
||||
const <name>: <type> := <value>
|
||||
```
|
||||
|
||||
Since a constant is categorized as a [definition](general-syntax.md#definitions)
|
||||
is uses the `is` keyword rather than the `:=` operator.
|
||||
|
||||
## Restrictions
|
||||
|
||||
Constants are subject to the following restrictions:
|
||||
|
|
|
@ -9,7 +9,7 @@ class (and instance) definitions.
|
|||
All definitions adhere to the following syntax:
|
||||
|
||||
```
|
||||
[export] <definition type> <name> <description> is <body>
|
||||
[export] <definition type> <name> <description> <body>
|
||||
```
|
||||
|
||||
Each definition type ultimately controls the description and body. All
|
||||
|
|
|
@ -5,11 +5,17 @@ Enumerations are sum types.
|
|||
## Example: The Option Type
|
||||
|
||||
```
|
||||
enum Option[A] is
|
||||
record Some[A] is (value: A)
|
||||
given A
|
||||
enum Option
|
||||
given A
|
||||
record Some (value: A)
|
||||
object None
|
||||
end enum
|
||||
|
||||
fn some[A]: (a: A) => Some[A] is a => Some(a)
|
||||
given A
|
||||
fn some: (a: A) => Some[A]
|
||||
a => Some (a)
|
||||
end fn
|
||||
```
|
||||
|
||||
## Example: The Either Type
|
||||
|
@ -17,10 +23,19 @@ fn some[A]: (a: A) => Some[A] is a => Some(a)
|
|||
TODO: Describe import behavior! Does importing Either import Left/Right?
|
||||
|
||||
```
|
||||
enum Either[L, R] is
|
||||
record Left[L] is { value: L }
|
||||
record Right[R] is { value: R }
|
||||
given L, R
|
||||
enum Either
|
||||
given L
|
||||
record Left (value: L)
|
||||
|
||||
fn left[L]: (left: L) => Either[L, Nothing] is l => Left { l }
|
||||
fn right[R]: (right: R) => Either[Nothing, R] is r => Right { r }
|
||||
given R
|
||||
record Right (value: R)
|
||||
|
||||
given L
|
||||
fn left: (left: L) => Either<L, Nothing> := l => Left(l)
|
||||
end fn
|
||||
|
||||
given R
|
||||
fn right: (right: R) => Either<Nothing, R> := Right(r)
|
||||
end fn
|
||||
```
|
||||
|
|
15
examples.md
Normal file
15
examples.md
Normal file
|
@ -0,0 +1,15 @@
|
|||
# Examples
|
||||
|
||||
## Hello, World!
|
||||
|
||||
```
|
||||
namespace example;
|
||||
|
||||
fn exit_success: () => ExitCode
|
||||
exit(0)
|
||||
|
||||
export fn main: (args: Array[String]) => Task[ExitCode]
|
||||
println ("Hello, World!") -> exit_success
|
||||
|
||||
-- map (println ("Hi")) (exit_success)
|
||||
```
|
107
functions.md
107
functions.md
|
@ -1,34 +1,97 @@
|
|||
# Functions
|
||||
|
||||
TODO: Scala syntax? Haskell syntax? Implications? How do we specify names for
|
||||
parameters? Do we want to do that? How do function arguments, tuples, and
|
||||
records all relate to one another? Are they all just the same? How do we talk
|
||||
about curried functions? Is that supported? Is there some other mechanism?
|
||||
|
||||
TODO: This is all 100% up in the air right now.
|
||||
## Syntax
|
||||
|
||||
```
|
||||
fn example: () => Int32 is 42
|
||||
example
|
||||
example()
|
||||
[given T1, T2, ... TN]
|
||||
fn <name>: <input> => <output> :=
|
||||
<body>
|
||||
end fn
|
||||
```
|
||||
|
||||
- `TN`: Type declaration (e.g. A :: Show)
|
||||
- `name`: Follows the rules for [names](names.md)
|
||||
- `input`: One or more named tuples ([records](records.md)).
|
||||
- `output`: Some type.
|
||||
- `body`: Function definition.
|
||||
|
||||
Note that `<input> => <output>` is the type of a function.
|
||||
|
||||
## Function Definitions
|
||||
|
||||
Function definitions are a series of expressions, where the value of the last
|
||||
expression is returned.
|
||||
|
||||
```
|
||||
fn example: (x: Int32, y: Int32) => Int32
|
||||
let xx := x + 1
|
||||
let yy := y + 1
|
||||
xx * yy
|
||||
end fn
|
||||
```
|
||||
|
||||
## Calling Functions
|
||||
|
||||
Calling a function involves passing that function the tuples it needs.
|
||||
|
||||
```
|
||||
given A :: Show
|
||||
fn example: (a: A) => String
|
||||
show(a)
|
||||
end fn
|
||||
|
||||
fn calling_a_function: () => Task[()]
|
||||
let x := 1
|
||||
let y := true
|
||||
let z := "foo"
|
||||
println(show(x) + show(y) + show(z))
|
||||
end fn
|
||||
```
|
||||
|
||||
### Calling with Tuples
|
||||
|
||||
```
|
||||
fn example: (x: Int32, y: Int32: z: Int32) => Int32
|
||||
x + y + z
|
||||
end fn
|
||||
|
||||
let inputs := (10, 20, 30)
|
||||
example inputs
|
||||
```
|
||||
|
||||
```
|
||||
fn example: String => Int32 is str => length(str)
|
||||
example "foo"
|
||||
example("foo")
|
||||
fn example: (x: Int32, y: Int32)(z: Int32, w: Int32) => Int32
|
||||
x + y + z + w
|
||||
end fn
|
||||
|
||||
let in1 := (1, 2)
|
||||
let in2 := (3, 4)
|
||||
example in1 in2
|
||||
example (1, 2) in2
|
||||
example in1 (3, 4)
|
||||
```
|
||||
|
||||
```
|
||||
fn example: { x: Int32, y: Int32 } => Int32 is (x, y) => x + y
|
||||
example 1 2
|
||||
example(1, 2)
|
||||
example { x: 1, y: 2 }
|
||||
```
|
||||
## Generic Functions
|
||||
|
||||
## Referencing Arguments
|
||||
|
||||
`@args` refers to function arguments.
|
||||
|
||||
- For a single parameter list, it refers to the record.
|
||||
- For multiple parameter lists, it refers to a tuple containing the lists in
|
||||
order.
|
||||
|
||||
## Lazy Arguments
|
||||
|
||||
The `lazy` keyword allows the expression providing the value to have evaluation
|
||||
deferred until the value is _used_ in the function. If the value is not used,
|
||||
the expression is never evaluated.
|
||||
|
||||
```
|
||||
fn map[F[*], A, B]: (F[A]) => (A => B) => F[B] is
|
||||
(fa) (f) => fa f
|
||||
|
||||
map(list)(x => x + 1)
|
||||
fn foo: (lazy x: Int32) => Int32
|
||||
x * 2
|
||||
end fn
|
||||
```
|
||||
|
||||
Note that this is equivalent to encoding a parameter as a synchronous effect and
|
||||
evaluating it to value when needed.
|
||||
|
|
33
infix-operators.md
Normal file
33
infix-operators.md
Normal file
|
@ -0,0 +1,33 @@
|
|||
# Infix Operators
|
||||
|
||||
Example of defining `->` to do `map` for any functor:
|
||||
|
||||
```
|
||||
given F[*] :: Functor, A, B
|
||||
infix -> (fa: F[A], f: (A) => B) => F[B] :=
|
||||
map (fa) (f)
|
||||
```
|
||||
|
||||
```
|
||||
let xs: List[Int] := list(1, 2, 3)
|
||||
let addOne := (x: Int32) => x + 1
|
||||
|
||||
-- [2, 3, 4]
|
||||
let ys := xs -> addOne
|
||||
|
||||
-- [4, 5, 6]
|
||||
let zs := xs -> addOne -> addOne -> addOne
|
||||
-- note, in order precedence: ((xs -> addOne) -> addOne) -> addOne
|
||||
```
|
||||
|
||||
## Precedence
|
||||
|
||||
In order precedence.
|
||||
|
||||
## Using Parentheses to Group
|
||||
|
||||
Infix operators for numeric operations are defined for tuples of size one.
|
||||
|
||||
```
|
||||
(12 - 2) / 2
|
||||
```
|
1
names.md
1
names.md
|
@ -12,7 +12,6 @@ Names are UTF-8 strings. The following values are _excluded_:
|
|||
- `=`
|
||||
- `"` or `'`
|
||||
- `[` or `]`
|
||||
- `{` or `}`
|
||||
- `(` or `)`
|
||||
|
||||
## Convention
|
||||
|
|
12
records.md
12
records.md
|
@ -5,7 +5,7 @@ records are just [tuples](tuples.md) with named fields. In many ways, the two
|
|||
can be interchanged.
|
||||
|
||||
```
|
||||
record Foo is (x: String, y: Int32)
|
||||
record Foo (x: String, y: Int32)
|
||||
```
|
||||
|
||||
Record fields are both _ordered_ and _named_.
|
||||
|
@ -31,13 +31,13 @@ Records do _not_ need to be named.
|
|||
Records may have generically typed data, and accept a type constructor:
|
||||
|
||||
```
|
||||
record Foo[A, B] is (x: A, y: B)
|
||||
record Foo[A, B] (x: A, y: B)
|
||||
```
|
||||
|
||||
## Instantiating Records
|
||||
|
||||
```
|
||||
record Foo is (x: String, y: Int32)
|
||||
record Foo (x: String, y: Int32)
|
||||
|
||||
let foo1 := Foo("foo", 1)
|
||||
let foo2 := Foo(x := "foo", y := 1)
|
||||
|
@ -49,7 +49,7 @@ Copy syntax allows any record to be duplicated, with any fields explicitly
|
|||
overridden by some value:
|
||||
|
||||
```
|
||||
record Foo is (x: String, y: Int32)
|
||||
record Foo (x: String, y: Int32)
|
||||
|
||||
let foo := Foo("foo", 1)
|
||||
let bar := copy(foo)
|
||||
|
@ -61,7 +61,7 @@ let baz := copy(foo, ("y": 2))
|
|||
The `.` operator is used to access individual fields on a record.
|
||||
|
||||
```
|
||||
record Foo is (x: String, y: Int32)
|
||||
record Foo (x: String, y: Int32)
|
||||
|
||||
let foo := Foo("foo", 1)
|
||||
let bar := foo.x
|
||||
|
@ -78,7 +78,7 @@ let baz: Int32 := foo._2
|
|||
Use the following record definition for this section:
|
||||
|
||||
```
|
||||
record Foo is (x: String, y: Int32)
|
||||
record Foo (x: String, y: Int32)
|
||||
```
|
||||
|
||||
Tuples can be assigned from records.
|
||||
|
|
|
@ -24,4 +24,8 @@
|
|||
- [Holes](holes.md)
|
||||
- [Pattern Matching](pattern-matching.md)
|
||||
- [Recursion](recursion.md)
|
||||
- [Infix Operators](infix-operators.md)
|
||||
- [Standard Library](standard-library.md)
|
||||
- [Examples](examples.md)
|
||||
- [Standard Types](standard-types.md)
|
||||
- [Numeric Overflow](numeric-overflow.md)
|
||||
|
|
10
tuples.md
10
tuples.md
|
@ -11,6 +11,16 @@ let x := ()
|
|||
let y := ("foo")
|
||||
let z := ("foo", 1)
|
||||
let w := ("foo", 1, true, 3.14)
|
||||
let a: Int32 := unwrap(1)
|
||||
```
|
||||
|
||||
Unwrapping a tuple of size one is just the identity function:
|
||||
|
||||
```
|
||||
given A
|
||||
fn unwrap: (a: A) => A
|
||||
a
|
||||
end fn
|
||||
```
|
||||
|
||||
## Type of a Standard Tuple
|
||||
|
|
27
types.md
27
types.md
|
@ -26,13 +26,14 @@ Types may directly, at the top level, be defined in terms of some
|
|||
[type constructor](#type-constructors):
|
||||
|
||||
```
|
||||
type TupleList[A, B] is List[(A, B)]
|
||||
given A, B
|
||||
type TupleList := List[(A, B)]
|
||||
```
|
||||
|
||||
Or in general terms:
|
||||
|
||||
```
|
||||
type <type constructor> is <type definition>
|
||||
type <type constructor> := <type definition>
|
||||
```
|
||||
|
||||
### Type Constructors
|
||||
|
@ -41,7 +42,8 @@ Type constructors essentially allow for types to be defined in terms of some set
|
|||
of type inputs. Consider the prior example:
|
||||
|
||||
```
|
||||
type TupleList[A, B] is List[(A, B)]
|
||||
given A, B
|
||||
type TupleList := List[(A, B)]
|
||||
```
|
||||
|
||||
The `TupleList` type requires two type arguments, `A` and `B`, to be constructed
|
||||
|
@ -52,16 +54,21 @@ as a concrete type. For example, `TupleList[String, Int32]` is a concrete type.
|
|||
Type constructors in Ava may be higher order (e.g. not order 1) functions:
|
||||
|
||||
```
|
||||
// Assume this exists
|
||||
type List[A] is ???
|
||||
fn map[A, B]: (List[A], (A) => B) => List[B]
|
||||
given A
|
||||
type List is ???
|
||||
|
||||
type class Functor[F[*]] is
|
||||
fn map[A, B]: (F[A])((A) => B) => F[B]
|
||||
given A, B
|
||||
fn map_list: (List[A], (A) => B) => List[B]
|
||||
|
||||
given F[*]
|
||||
type class Functor is
|
||||
given A, B
|
||||
fn map: (F[A])((A) => B) => F<B>
|
||||
|
||||
instance Functor[List] is
|
||||
fn map[A, B]: (List[A])((A) => B) => List[B] is
|
||||
(list)(f) => map(list, f)
|
||||
given A, B
|
||||
fn map: (List[A])((A) => B) => [B] :=
|
||||
(list)(f) => map_list (list, f)
|
||||
```
|
||||
|
||||
In this example, `Functor[F[*]]` is a type constructor which accepts a single
|
||||
|
|
Loading…
Add table
Reference in a new issue