Big changes/progress, functions are finally becoming decent.
This commit is contained in:
parent
2ad400167a
commit
6a08ad31f0
7 changed files with 127 additions and 114 deletions
37
ava.ebnf
37
ava.ebnf
|
@ -52,10 +52,20 @@ k_object ::= 'o', 'b', 'j', 'e', 'c', 't';
|
|||
k_let ::= 'l', 'e', 't';
|
||||
k_mut ::= 'm', 'u', 't';
|
||||
k_export ::= 'e', 'x', 'p', 'o', 'r', 't';
|
||||
|
||||
(* Starts an import definition. *)
|
||||
k_import ::= 'i', 'm', 'p', 'o', 'r', 't';
|
||||
|
||||
(* Denotes a namespace declaration. *)
|
||||
k_namespace ::= 'n', 'a', 'm', 'e', 's', 'p', 'a', 'c', 'e';
|
||||
|
||||
(* Starts an infix function definition *)
|
||||
k_infix ::= 'i', 'n', 'f', 'i', 'x';
|
||||
|
||||
(* Starts a function definition. *)
|
||||
k_fn ::= 'f', 'n';
|
||||
|
||||
(* Ends any block definition. Must be followed by the keyword of the block. *)
|
||||
k_end ::= 'e', 'n', 'd';
|
||||
|
||||
(* Initiates a pattern match against some value. *)
|
||||
|
@ -63,6 +73,7 @@ k_match ::= 'm', 'a', 't', 'c', 'h';
|
|||
|
||||
(* Initiates a pattern matching case. Applicable to functions and matches. *)
|
||||
k_case ::= 'c', 'a', 's', 'e';
|
||||
k_lambda ::= 'λ';
|
||||
|
||||
(* Used in if/else syntax. Starts such a block and used in 'else if'. *)
|
||||
k_if ::= 'i', 'f';
|
||||
|
@ -94,8 +105,8 @@ k_false ::= 'f', 'a', 'l', 's', 'e';
|
|||
keyword ::= k_type | k_class | k_alias | k_const | k_enum | k_record
|
||||
| k_object | k_let | k_mut | k_export | k_import
|
||||
| k_namespace | k_infix | k_fn | k_end | k_match | k_case
|
||||
| k_if | k_then | k_else | k_do | k_return | k_given
|
||||
| k_private | k_true | k_false;
|
||||
| k_lambda | k_if | k_then | k_else | k_do | k_return
|
||||
| k_given | k_private | k_true | k_false;
|
||||
|
||||
(* ============== *)
|
||||
(* Literal Values *)
|
||||
|
@ -106,7 +117,7 @@ literal_integer ::= ['-'], number_integer;
|
|||
literal_float ::= ['-'], number_float;
|
||||
literal_char ::= "'", char_char, "'";
|
||||
literal_string ::= '"', {string_char}, "'";
|
||||
empty_tuple ::= lparen, rparen;
|
||||
empty_tuple ::= op_tuple, lparen, rparen;
|
||||
empty_list ::= lbracket, rbracket;
|
||||
literal ::= literal_bool
|
||||
| literal_integer
|
||||
|
@ -124,6 +135,9 @@ literal ::= literal_bool
|
|||
runtime. *)
|
||||
hole ::= '?', '?', '?';
|
||||
|
||||
(* Used for splat imports: import foo.bar.baz.* is an example. *)
|
||||
op_import_splat ::= '*';
|
||||
|
||||
(* Used to access members. Relevant for namespaces, records, enums, classes. *)
|
||||
op_member ::= '.';
|
||||
|
||||
|
@ -134,7 +148,7 @@ op_comma ::= ',';
|
|||
op_type_union ::= '|';
|
||||
|
||||
(* List operator. Prepend LHS to RHS. Can be used in pattern matching. *)
|
||||
op_list_prepend ::= ':';
|
||||
op_list_prepend ::= ':', '-';
|
||||
|
||||
(* Only valid adjacent to a name declaration. Explicitly declare the type that
|
||||
the name has. *)
|
||||
|
@ -153,9 +167,22 @@ op_bind_do ::= '<', '-';
|
|||
(* Indicates some type is constrained by some type class, ex F * :: Functor *)
|
||||
op_class_member ::= ':', ':';
|
||||
|
||||
(* Indicates the start of a case, case <pattern> => <expr> *)
|
||||
(* Indicates the start of a pattern matching case, used in both forms:
|
||||
|
||||
case <pattern> => <expr>
|
||||
λ <pattern> => <expr>
|
||||
|
||||
The λ form is preferred for functions, 'case' is preferred for 'match'. *)
|
||||
op_case ::= '=', '>';
|
||||
|
||||
(* Declares a tuple, as in #(a, b, c) *)
|
||||
op_tuple ::= '#';
|
||||
|
||||
operator ::= hole | op_import_splat | op_member | op_comma
|
||||
| op_type_union | op_list_prepend | op_bind_type
|
||||
| op_bind_value | op_fn_return | -> op_bind_do
|
||||
| op_class_member | op_case | op_tuple;
|
||||
|
||||
(* ===== *)
|
||||
(* Names *)
|
||||
(* ===== *)
|
||||
|
|
|
@ -24,6 +24,10 @@ instance Functor List
|
|||
case f [h : t] => f h : map f t
|
||||
end fn
|
||||
end instance
|
||||
|
||||
-- Equivalent to F[*[*]]
|
||||
given F (* *), C, B
|
||||
fn example: F (C B) -> B
|
||||
```
|
||||
|
||||
```
|
||||
|
|
29
lists.md
29
lists.md
|
@ -1,14 +1,15 @@
|
|||
# Lists
|
||||
|
||||
Lists are a standard Ava type. Specifically, `List[A]` represents a linked list.
|
||||
Lists are a standard Ava type. Specifically `[A]` represents a linked list.
|
||||
|
||||
```
|
||||
let x: List[Int32] := { 1, 2, 3 }
|
||||
let y := prepend(x, 0)
|
||||
let z := append(x, { 4, 5 })
|
||||
let w: Option[Int32] := head(x)
|
||||
let tail: List[Int32] := tail(x)
|
||||
let sz: List[Int32] := size(x)
|
||||
let x: [Int32] := [1, 2, 3]
|
||||
let y := prepend x 0
|
||||
let alt_y := 0 :- x
|
||||
let z := append x [4, 5]
|
||||
let w: Option[Int32] := head x
|
||||
let tail: [Int32] := tail x
|
||||
let sz: [Int32] := size x
|
||||
```
|
||||
|
||||
## Type Class Support
|
||||
|
@ -24,21 +25,9 @@ The type `NonEmptyList` is a list which cannot be empty:
|
|||
|
||||
```
|
||||
given A
|
||||
record NonEmptyList: (head: A, tail: List[A])
|
||||
record NonEmptyList(head: A, tail: [A])
|
||||
```
|
||||
|
||||
## Indexing
|
||||
|
||||
Lists cannot be accessed by index.
|
||||
|
||||
## Implementation
|
||||
|
||||
```
|
||||
given A
|
||||
enum List
|
||||
object Nil
|
||||
|
||||
given A
|
||||
record List(head: A, tail: List[A])
|
||||
end enum
|
||||
```
|
||||
|
|
1
names.md
1
names.md
|
@ -12,7 +12,6 @@ Names are UTF-8 strings. The following values are _excluded_:
|
|||
- `"`
|
||||
- `,`
|
||||
- `\`
|
||||
- `[` or `]`
|
||||
- `(` or `)`
|
||||
|
||||
## Convention
|
||||
|
|
55
records.md
55
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 (x: String, y: Int32)
|
||||
record Foo(x: String, y: Int32)
|
||||
```
|
||||
|
||||
Record fields are both _ordered_ and _named_.
|
||||
|
@ -23,7 +23,7 @@ Record fields are both _ordered_ and _named_.
|
|||
Records do _not_ need to be named.
|
||||
|
||||
```
|
||||
(x: String, y: String, z: String)
|
||||
#(x: String, y: String, z: String)
|
||||
```
|
||||
|
||||
## Generic Records
|
||||
|
@ -32,7 +32,7 @@ Records may have generically typed data, and accept a type constructor:
|
|||
|
||||
```
|
||||
given A, B
|
||||
record Foo (x: A, y: B)
|
||||
record Foo(x: A, y: B)
|
||||
```
|
||||
|
||||
## Instantiating Records
|
||||
|
@ -41,7 +41,10 @@ record Foo (x: A, y: B)
|
|||
record Foo (x: String, y: Int32)
|
||||
|
||||
let foo1 := Foo("foo", 1)
|
||||
let foo2 := Foo(x := "foo", y := 1)
|
||||
let foo2 := Foo(
|
||||
x := "foo",
|
||||
y := 1
|
||||
)
|
||||
```
|
||||
|
||||
## Copying Data
|
||||
|
@ -50,11 +53,11 @@ Copy syntax allows any record to be duplicated, with any fields explicitly
|
|||
overridden by some value:
|
||||
|
||||
```
|
||||
record Foo (x: String, y: Int32)
|
||||
record Foo(x: String, y: Int32)
|
||||
|
||||
let foo := Foo("foo", 1)
|
||||
let bar := copy(foo)
|
||||
let baz := copy(foo, ("y": 2))
|
||||
let bar := copy foo
|
||||
let baz := copy foo #(y := 2)
|
||||
```
|
||||
|
||||
## Accessing Record Data
|
||||
|
@ -62,7 +65,7 @@ let baz := copy(foo, ("y": 2))
|
|||
The `.` operator is used to access individual fields on a record.
|
||||
|
||||
```
|
||||
record Foo (x: String, y: Int32)
|
||||
record Foo(x: String, y: Int32)
|
||||
|
||||
let foo := Foo("foo", 1)
|
||||
let bar := foo.x
|
||||
|
@ -75,45 +78,43 @@ Tuple syntax is _not_ supported on records.
|
|||
Use the following record definition for this section:
|
||||
|
||||
```
|
||||
record Foo (x: String, y: Int32)
|
||||
record Foo(x: String, y: Int32)
|
||||
```
|
||||
|
||||
Tuples can be assigned from records.
|
||||
|
||||
```
|
||||
let foo := Foo("foo", 1)
|
||||
let some_tuple: (String, Int32) := foo
|
||||
let some_tuple: #(String, Int32) := foo
|
||||
```
|
||||
|
||||
Records can be assigned from tuples.
|
||||
|
||||
```
|
||||
let some_tuple := ("foo", 1)
|
||||
let some_tuple := #("foo", 1)
|
||||
let foo: Foo := some_tuple
|
||||
```
|
||||
|
||||
Records can be cast to tuples by extracting the tuple metadata from the record.
|
||||
Records can be cast to tuples if the types/ordering are identical.
|
||||
|
||||
```
|
||||
let foo := Foo("foo", 1)
|
||||
let bar: (String, Int32) := @foo.tuple
|
||||
```
|
||||
|
||||
TODO: Metdata is up in the air.
|
||||
|
||||
Records respect the tuple size metadata.
|
||||
|
||||
```
|
||||
let size := @foo.size
|
||||
```
|
||||
|
||||
Records provide field metadata.
|
||||
|
||||
```
|
||||
let desc: RecordDescription := @foo.description
|
||||
let bar: #(String, Int32) := foo
|
||||
```
|
||||
|
||||
## Destructuring Records
|
||||
|
||||
Records can be _destructured_ via [pattern matching](pattern-matching.md)
|
||||
capabilities.
|
||||
|
||||
```
|
||||
record Foo(x: String, y: Int32)
|
||||
|
||||
let foo := Foo("foo", 1)
|
||||
|
||||
match foo
|
||||
case "foo" _ => "bar"
|
||||
case _ 2 => "baz"
|
||||
case _ _ => "legume"
|
||||
end match
|
||||
```
|
||||
|
|
|
@ -1,17 +1,14 @@
|
|||
# Standard Type Classes
|
||||
|
||||
```
|
||||
--- Associative binary operation.
|
||||
--- **Associative**: `combine(x, combine(y, z)) = combine(combine(x, y), z)`
|
||||
given A
|
||||
class Semigroup
|
||||
fn combine(x: A, y: A): A
|
||||
fn combine: A -> A -> A
|
||||
end class
|
||||
|
||||
--- **Empty Identity**: `combine(x, empty()) = combine(empty(), x) = x`
|
||||
given A :: Semigroup
|
||||
class Monoid
|
||||
fn empty() => A
|
||||
fn empty: A
|
||||
end class
|
||||
|
||||
--- Type class for type constructors which can be mapped over.
|
||||
|
@ -20,7 +17,7 @@ end class
|
|||
---
|
||||
--- **Composition**: `fa -> f -> g = fa -> (f ∘ g)`
|
||||
--- **Identity**: `fa -> ((x) => x) = fa`
|
||||
given F[*]
|
||||
given F *
|
||||
class Functor
|
||||
--- Transform some wrapped data from one type to another, preserving the
|
||||
--- wrapper.
|
||||
|
@ -29,105 +26,99 @@ class Functor
|
|||
--- @tparam B The type of output data.
|
||||
--- @param fa The functor input.
|
||||
--- @param f The function to transform data from `A` to `B`.
|
||||
given [A, B]
|
||||
fn map: (fa: F[A])(f: (A) => B) => F[B]
|
||||
given A, B
|
||||
fn map: F A -> (A -> B) -> F B
|
||||
end class
|
||||
|
||||
-- Need Laws
|
||||
given F[*] :: Functor
|
||||
given F * :: Functor
|
||||
class Apply
|
||||
given A, B
|
||||
fn ap: (ff: F[(A) => B])(fa: F[A]) => F[B]
|
||||
fn ap: F (A -> B) -> F A -> F B
|
||||
end class
|
||||
|
||||
-- Need Laws
|
||||
given F[*] :: Apply
|
||||
given F * :: Apply
|
||||
class Applicative
|
||||
given A
|
||||
fn pure: (value: A) => F[A]
|
||||
fn pure: A -> F A
|
||||
|
||||
fn unit: () => F[()]
|
||||
pure(())
|
||||
fn unit: F ()
|
||||
pure ()
|
||||
end fn
|
||||
end class
|
||||
|
||||
--- Any Applicative satisfies Functor.
|
||||
given F[*] :: Applicative
|
||||
instance Functor[F]
|
||||
given F * :: Applicative
|
||||
instance Functor F
|
||||
given A, B
|
||||
fn map: (fa: F[A])(f: (A) => B) => F[B]
|
||||
ap(pure(f))(fa)
|
||||
fn map: F A -> (A -> B) -> F B
|
||||
fa f => ap (pure f) fa
|
||||
end fn
|
||||
end instance
|
||||
|
||||
given F[*] :: Apply
|
||||
given F * :: Apply
|
||||
class FlatMap
|
||||
given A, B
|
||||
fn fmap: (fa: F[A])(f: (A) => F[B]) => F[B]
|
||||
fn fmap: F A -> (A -> F B) -> F B
|
||||
|
||||
given A
|
||||
fn flatten: (ffa: F[F[A]]) => F[A]
|
||||
fmap(ffa)((fa) => fa)
|
||||
fn flatten: F (F A) -> F A
|
||||
ffa => fmap ffa (fa => fa)
|
||||
end fn
|
||||
end class
|
||||
|
||||
given F[*] :: FlatMap, Applicative
|
||||
given F * :: FlatMap, Applicative
|
||||
class Monad
|
||||
end class
|
||||
|
||||
--- Any Monad satisfies Functor.
|
||||
--- Note for type class spec, must account for "override" precedence
|
||||
given F[*] :: Applicative
|
||||
instance Functor[F]
|
||||
fn map: (fa: F[A])(f: (A) => B) => F[B]
|
||||
fmap(fa)((a) => pure(f(a)))
|
||||
given F * :: Monad
|
||||
instance Functor F
|
||||
fn map: F A -> (A -> B) -> F B
|
||||
λ fa f => fmap fa (λ a => pure (f a))
|
||||
end fn
|
||||
end instance
|
||||
|
||||
given F[*, *]
|
||||
given F * *
|
||||
class Bifunctor
|
||||
def bimap[A, B, C, D](fab: F[A, B])(f: A => C, g: B => D): F[C, D]
|
||||
|
||||
given A, B, C, D
|
||||
fn bimap(fab: F[A, B])(f: (A) => C, g: (B) => D) => F[C, D]
|
||||
fn bimap F A B -> (A -> C) -> (B -> D) -> F C D
|
||||
end class
|
||||
|
||||
given F[*] :: Functor
|
||||
given F * :: Functor
|
||||
class CoFlatMap
|
||||
given A, B
|
||||
fn cofmap: (fa: F[A])(f: (F[A]) => B) => F[B]
|
||||
fn cofmap: F A -> (F A -> B) -> F B
|
||||
|
||||
given A
|
||||
fn coflatten: (fa: F[A]) => F[F[A]]
|
||||
cofmap(fa)((fa) => fa)
|
||||
fn coflatten: F A -> F (F A)
|
||||
λ fa => cofmap fa (λ f => f)
|
||||
end fn
|
||||
end class
|
||||
|
||||
given F[*] :: CoFlatMap
|
||||
given F * :: CoFlatMap
|
||||
class CoMonad
|
||||
given A
|
||||
fn extract: (fa: F[A]) => A
|
||||
fn extract: F A -> A
|
||||
end class
|
||||
|
||||
given A
|
||||
class Show
|
||||
fn show: (value: A) => String
|
||||
fn show: A -> String
|
||||
end class
|
||||
|
||||
given A, B
|
||||
class Eq
|
||||
fn eq: (x: A, y: B) => Boolean
|
||||
fn eq: A -> B -> Boolean
|
||||
|
||||
fn neq: (x: A, y: B) => Boolean
|
||||
not(eq(x, y))
|
||||
fn neq: A -> B -> Boolean
|
||||
λ x y => not (eq x y)
|
||||
end fn
|
||||
|
||||
infix =: (x: A, y: B) => Boolean
|
||||
eq(x, y)
|
||||
infix =: A -> B -> Boolean
|
||||
λ x y => eq x y
|
||||
end infix
|
||||
|
||||
infix !=: (x: A, y: B) => Boolean
|
||||
neq(x, y)
|
||||
infix !=: A -> B -> Boolean
|
||||
λ x y => neq x y
|
||||
end infix
|
||||
end class
|
||||
|
||||
|
@ -139,20 +130,22 @@ end enum
|
|||
|
||||
given A
|
||||
class Compare
|
||||
fn compare: (x: A, y: A) => Comparison
|
||||
fn compare: A -> A -> Comparison
|
||||
end class
|
||||
|
||||
given A
|
||||
instance Eq[A, A]
|
||||
fn eq: (x: A, y: A) => Boolean
|
||||
match compare(x, y)
|
||||
case EqualTo => true
|
||||
case _ => false
|
||||
given A :: Compare
|
||||
instance Eq A A
|
||||
fn eq: A -> A -> Boolean
|
||||
λ x y =>
|
||||
match compare x y
|
||||
case EqualTo => true
|
||||
case _ => false
|
||||
end match
|
||||
end fn
|
||||
end instance
|
||||
|
||||
given A
|
||||
class HashCode
|
||||
fn hash_code(data: A) => Int32
|
||||
fn hash_code: A -> Int32
|
||||
end class
|
||||
```
|
||||
|
|
|
@ -7,10 +7,10 @@ but records have named parameters.
|
|||
## Syntax
|
||||
|
||||
```
|
||||
let x := ()
|
||||
let y := ("foo")
|
||||
let z := ("foo", 1)
|
||||
let w := ("foo", 1, true, 3.14)
|
||||
let x := #()
|
||||
let y := #("foo")
|
||||
let z := #("foo", 1)
|
||||
let w := #("foo", 1, true, 3.14)
|
||||
```
|
||||
|
||||
## Type of a Standard Tuple
|
||||
|
|
Loading…
Add table
Reference in a new issue