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_let ::= 'l', 'e', 't';
|
||||||
k_mut ::= 'm', 'u', 't';
|
k_mut ::= 'm', 'u', 't';
|
||||||
k_export ::= 'e', 'x', 'p', 'o', 'r', 't';
|
k_export ::= 'e', 'x', 'p', 'o', 'r', 't';
|
||||||
|
|
||||||
|
(* Starts an import definition. *)
|
||||||
k_import ::= 'i', 'm', 'p', 'o', 'r', 't';
|
k_import ::= 'i', 'm', 'p', 'o', 'r', 't';
|
||||||
|
|
||||||
|
(* Denotes a namespace declaration. *)
|
||||||
k_namespace ::= 'n', 'a', 'm', 'e', 's', 'p', 'a', 'c', 'e';
|
k_namespace ::= 'n', 'a', 'm', 'e', 's', 'p', 'a', 'c', 'e';
|
||||||
|
|
||||||
|
(* Starts an infix function definition *)
|
||||||
k_infix ::= 'i', 'n', 'f', 'i', 'x';
|
k_infix ::= 'i', 'n', 'f', 'i', 'x';
|
||||||
|
|
||||||
|
(* Starts a function definition. *)
|
||||||
k_fn ::= 'f', 'n';
|
k_fn ::= 'f', 'n';
|
||||||
|
|
||||||
|
(* Ends any block definition. Must be followed by the keyword of the block. *)
|
||||||
k_end ::= 'e', 'n', 'd';
|
k_end ::= 'e', 'n', 'd';
|
||||||
|
|
||||||
(* Initiates a pattern match against some value. *)
|
(* 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. *)
|
(* Initiates a pattern matching case. Applicable to functions and matches. *)
|
||||||
k_case ::= 'c', 'a', 's', 'e';
|
k_case ::= 'c', 'a', 's', 'e';
|
||||||
|
k_lambda ::= 'λ';
|
||||||
|
|
||||||
(* Used in if/else syntax. Starts such a block and used in 'else if'. *)
|
(* Used in if/else syntax. Starts such a block and used in 'else if'. *)
|
||||||
k_if ::= 'i', 'f';
|
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
|
keyword ::= k_type | k_class | k_alias | k_const | k_enum | k_record
|
||||||
| k_object | k_let | k_mut | k_export | k_import
|
| k_object | k_let | k_mut | k_export | k_import
|
||||||
| k_namespace | k_infix | k_fn | k_end | k_match | k_case
|
| 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_lambda | k_if | k_then | k_else | k_do | k_return
|
||||||
| k_private | k_true | k_false;
|
| k_given | k_private | k_true | k_false;
|
||||||
|
|
||||||
(* ============== *)
|
(* ============== *)
|
||||||
(* Literal Values *)
|
(* Literal Values *)
|
||||||
|
@ -106,7 +117,7 @@ literal_integer ::= ['-'], number_integer;
|
||||||
literal_float ::= ['-'], number_float;
|
literal_float ::= ['-'], number_float;
|
||||||
literal_char ::= "'", char_char, "'";
|
literal_char ::= "'", char_char, "'";
|
||||||
literal_string ::= '"', {string_char}, "'";
|
literal_string ::= '"', {string_char}, "'";
|
||||||
empty_tuple ::= lparen, rparen;
|
empty_tuple ::= op_tuple, lparen, rparen;
|
||||||
empty_list ::= lbracket, rbracket;
|
empty_list ::= lbracket, rbracket;
|
||||||
literal ::= literal_bool
|
literal ::= literal_bool
|
||||||
| literal_integer
|
| literal_integer
|
||||||
|
@ -124,6 +135,9 @@ literal ::= literal_bool
|
||||||
runtime. *)
|
runtime. *)
|
||||||
hole ::= '?', '?', '?';
|
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. *)
|
(* Used to access members. Relevant for namespaces, records, enums, classes. *)
|
||||||
op_member ::= '.';
|
op_member ::= '.';
|
||||||
|
|
||||||
|
@ -134,7 +148,7 @@ op_comma ::= ',';
|
||||||
op_type_union ::= '|';
|
op_type_union ::= '|';
|
||||||
|
|
||||||
(* List operator. Prepend LHS to RHS. Can be used in pattern matching. *)
|
(* 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
|
(* Only valid adjacent to a name declaration. Explicitly declare the type that
|
||||||
the name has. *)
|
the name has. *)
|
||||||
|
@ -153,9 +167,22 @@ op_bind_do ::= '<', '-';
|
||||||
(* Indicates some type is constrained by some type class, ex F * :: Functor *)
|
(* Indicates some type is constrained by some type class, ex F * :: Functor *)
|
||||||
op_class_member ::= ':', ':';
|
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 ::= '=', '>';
|
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 *)
|
(* Names *)
|
||||||
(* ===== *)
|
(* ===== *)
|
||||||
|
|
|
@ -24,6 +24,10 @@ instance Functor List
|
||||||
case f [h : t] => f h : map f t
|
case f [h : t] => f h : map f t
|
||||||
end fn
|
end fn
|
||||||
end instance
|
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
|
||||||
|
|
||||||
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 x: [Int32] := [1, 2, 3]
|
||||||
let y := prepend(x, 0)
|
let y := prepend x 0
|
||||||
let z := append(x, { 4, 5 })
|
let alt_y := 0 :- x
|
||||||
let w: Option[Int32] := head(x)
|
let z := append x [4, 5]
|
||||||
let tail: List[Int32] := tail(x)
|
let w: Option[Int32] := head x
|
||||||
let sz: List[Int32] := size(x)
|
let tail: [Int32] := tail x
|
||||||
|
let sz: [Int32] := size x
|
||||||
```
|
```
|
||||||
|
|
||||||
## Type Class Support
|
## Type Class Support
|
||||||
|
@ -24,21 +25,9 @@ The type `NonEmptyList` is a list which cannot be empty:
|
||||||
|
|
||||||
```
|
```
|
||||||
given A
|
given A
|
||||||
record NonEmptyList: (head: A, tail: List[A])
|
record NonEmptyList(head: A, tail: [A])
|
||||||
```
|
```
|
||||||
|
|
||||||
## Indexing
|
## Indexing
|
||||||
|
|
||||||
Lists cannot be accessed by index.
|
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 `)`
|
- `(` or `)`
|
||||||
|
|
||||||
## Convention
|
## Convention
|
||||||
|
|
45
records.md
45
records.md
|
@ -23,7 +23,7 @@ Record fields are both _ordered_ and _named_.
|
||||||
Records do _not_ need to be named.
|
Records do _not_ need to be named.
|
||||||
|
|
||||||
```
|
```
|
||||||
(x: String, y: String, z: String)
|
#(x: String, y: String, z: String)
|
||||||
```
|
```
|
||||||
|
|
||||||
## Generic Records
|
## Generic Records
|
||||||
|
@ -41,7 +41,10 @@ record Foo (x: A, y: B)
|
||||||
record Foo (x: String, y: Int32)
|
record Foo (x: String, y: Int32)
|
||||||
|
|
||||||
let foo1 := Foo("foo", 1)
|
let foo1 := Foo("foo", 1)
|
||||||
let foo2 := Foo(x := "foo", y := 1)
|
let foo2 := Foo(
|
||||||
|
x := "foo",
|
||||||
|
y := 1
|
||||||
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
## Copying Data
|
## Copying Data
|
||||||
|
@ -53,8 +56,8 @@ overridden by some value:
|
||||||
record Foo(x: String, y: Int32)
|
record Foo(x: String, y: Int32)
|
||||||
|
|
||||||
let foo := Foo("foo", 1)
|
let foo := Foo("foo", 1)
|
||||||
let bar := copy(foo)
|
let bar := copy foo
|
||||||
let baz := copy(foo, ("y": 2))
|
let baz := copy foo #(y := 2)
|
||||||
```
|
```
|
||||||
|
|
||||||
## Accessing Record Data
|
## Accessing Record Data
|
||||||
|
@ -82,38 +85,36 @@ Tuples can be assigned from records.
|
||||||
|
|
||||||
```
|
```
|
||||||
let foo := Foo("foo", 1)
|
let foo := Foo("foo", 1)
|
||||||
let some_tuple: (String, Int32) := foo
|
let some_tuple: #(String, Int32) := foo
|
||||||
```
|
```
|
||||||
|
|
||||||
Records can be assigned from tuples.
|
Records can be assigned from tuples.
|
||||||
|
|
||||||
```
|
```
|
||||||
let some_tuple := ("foo", 1)
|
let some_tuple := #("foo", 1)
|
||||||
let foo: Foo := some_tuple
|
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 foo := Foo("foo", 1)
|
||||||
let bar: (String, Int32) := @foo.tuple
|
let bar: #(String, Int32) := foo
|
||||||
```
|
|
||||||
|
|
||||||
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
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Destructuring Records
|
## Destructuring Records
|
||||||
|
|
||||||
Records can be _destructured_ via [pattern matching](pattern-matching.md)
|
Records can be _destructured_ via [pattern matching](pattern-matching.md)
|
||||||
capabilities.
|
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
|
# Standard Type Classes
|
||||||
|
|
||||||
```
|
```
|
||||||
--- Associative binary operation.
|
|
||||||
--- **Associative**: `combine(x, combine(y, z)) = combine(combine(x, y), z)`
|
|
||||||
given A
|
given A
|
||||||
class Semigroup
|
class Semigroup
|
||||||
fn combine(x: A, y: A): A
|
fn combine: A -> A -> A
|
||||||
end class
|
end class
|
||||||
|
|
||||||
--- **Empty Identity**: `combine(x, empty()) = combine(empty(), x) = x`
|
|
||||||
given A :: Semigroup
|
given A :: Semigroup
|
||||||
class Monoid
|
class Monoid
|
||||||
fn empty() => A
|
fn empty: A
|
||||||
end class
|
end class
|
||||||
|
|
||||||
--- Type class for type constructors which can be mapped over.
|
--- Type class for type constructors which can be mapped over.
|
||||||
|
@ -20,7 +17,7 @@ end class
|
||||||
---
|
---
|
||||||
--- **Composition**: `fa -> f -> g = fa -> (f ∘ g)`
|
--- **Composition**: `fa -> f -> g = fa -> (f ∘ g)`
|
||||||
--- **Identity**: `fa -> ((x) => x) = fa`
|
--- **Identity**: `fa -> ((x) => x) = fa`
|
||||||
given F[*]
|
given F *
|
||||||
class Functor
|
class Functor
|
||||||
--- Transform some wrapped data from one type to another, preserving the
|
--- Transform some wrapped data from one type to another, preserving the
|
||||||
--- wrapper.
|
--- wrapper.
|
||||||
|
@ -29,105 +26,99 @@ class Functor
|
||||||
--- @tparam B The type of output data.
|
--- @tparam B The type of output data.
|
||||||
--- @param fa The functor input.
|
--- @param fa The functor input.
|
||||||
--- @param f The function to transform data from `A` to `B`.
|
--- @param f The function to transform data from `A` to `B`.
|
||||||
given [A, B]
|
given A, B
|
||||||
fn map: (fa: F[A])(f: (A) => B) => F[B]
|
fn map: F A -> (A -> B) -> F B
|
||||||
end class
|
end class
|
||||||
|
|
||||||
-- Need Laws
|
given F * :: Functor
|
||||||
given F[*] :: Functor
|
|
||||||
class Apply
|
class Apply
|
||||||
given A, B
|
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
|
end class
|
||||||
|
|
||||||
-- Need Laws
|
given F * :: Apply
|
||||||
given F[*] :: Apply
|
|
||||||
class Applicative
|
class Applicative
|
||||||
given A
|
given A
|
||||||
fn pure: (value: A) => F[A]
|
fn pure: A -> F A
|
||||||
|
|
||||||
fn unit: () => F[()]
|
fn unit: F ()
|
||||||
pure(())
|
pure ()
|
||||||
end fn
|
end fn
|
||||||
end class
|
end class
|
||||||
|
|
||||||
--- Any Applicative satisfies Functor.
|
--- Any Applicative satisfies Functor.
|
||||||
given F[*] :: Applicative
|
given F * :: Applicative
|
||||||
instance Functor[F]
|
instance Functor F
|
||||||
given A, B
|
given A, B
|
||||||
fn map: (fa: F[A])(f: (A) => B) => F[B]
|
fn map: F A -> (A -> B) -> F B
|
||||||
ap(pure(f))(fa)
|
fa f => ap (pure f) fa
|
||||||
end fn
|
end fn
|
||||||
end instance
|
end instance
|
||||||
|
|
||||||
given F[*] :: Apply
|
given F * :: Apply
|
||||||
class FlatMap
|
class FlatMap
|
||||||
given A, B
|
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
|
given A
|
||||||
fn flatten: (ffa: F[F[A]]) => F[A]
|
fn flatten: F (F A) -> F A
|
||||||
fmap(ffa)((fa) => fa)
|
ffa => fmap ffa (fa => fa)
|
||||||
end fn
|
end fn
|
||||||
end class
|
end class
|
||||||
|
|
||||||
given F[*] :: FlatMap, Applicative
|
given F * :: FlatMap, Applicative
|
||||||
class Monad
|
class Monad
|
||||||
end class
|
end class
|
||||||
|
|
||||||
--- Any Monad satisfies Functor.
|
given F * :: Monad
|
||||||
--- Note for type class spec, must account for "override" precedence
|
instance Functor F
|
||||||
given F[*] :: Applicative
|
fn map: F A -> (A -> B) -> F B
|
||||||
instance Functor[F]
|
λ fa f => fmap fa (λ a => pure (f a))
|
||||||
fn map: (fa: F[A])(f: (A) => B) => F[B]
|
|
||||||
fmap(fa)((a) => pure(f(a)))
|
|
||||||
end fn
|
end fn
|
||||||
end instance
|
end instance
|
||||||
|
|
||||||
given F[*, *]
|
given F * *
|
||||||
class Bifunctor
|
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
|
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
|
end class
|
||||||
|
|
||||||
given F[*] :: Functor
|
given F * :: Functor
|
||||||
class CoFlatMap
|
class CoFlatMap
|
||||||
given A, B
|
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
|
given A
|
||||||
fn coflatten: (fa: F[A]) => F[F[A]]
|
fn coflatten: F A -> F (F A)
|
||||||
cofmap(fa)((fa) => fa)
|
λ fa => cofmap fa (λ f => f)
|
||||||
end fn
|
end fn
|
||||||
end class
|
end class
|
||||||
|
|
||||||
given F[*] :: CoFlatMap
|
given F * :: CoFlatMap
|
||||||
class CoMonad
|
class CoMonad
|
||||||
given A
|
given A
|
||||||
fn extract: (fa: F[A]) => A
|
fn extract: F A -> A
|
||||||
end class
|
end class
|
||||||
|
|
||||||
given A
|
given A
|
||||||
class Show
|
class Show
|
||||||
fn show: (value: A) => String
|
fn show: A -> String
|
||||||
end class
|
end class
|
||||||
|
|
||||||
given A, B
|
given A, B
|
||||||
class Eq
|
class Eq
|
||||||
fn eq: (x: A, y: B) => Boolean
|
fn eq: A -> B -> Boolean
|
||||||
|
|
||||||
fn neq: (x: A, y: B) => Boolean
|
fn neq: A -> B -> Boolean
|
||||||
not(eq(x, y))
|
λ x y => not (eq x y)
|
||||||
end fn
|
end fn
|
||||||
|
|
||||||
infix =: (x: A, y: B) => Boolean
|
infix =: A -> B -> Boolean
|
||||||
eq(x, y)
|
λ x y => eq x y
|
||||||
end infix
|
end infix
|
||||||
|
|
||||||
infix !=: (x: A, y: B) => Boolean
|
infix !=: A -> B -> Boolean
|
||||||
neq(x, y)
|
λ x y => neq x y
|
||||||
end infix
|
end infix
|
||||||
end class
|
end class
|
||||||
|
|
||||||
|
@ -139,20 +130,22 @@ end enum
|
||||||
|
|
||||||
given A
|
given A
|
||||||
class Compare
|
class Compare
|
||||||
fn compare: (x: A, y: A) => Comparison
|
fn compare: A -> A -> Comparison
|
||||||
end class
|
end class
|
||||||
|
|
||||||
given A
|
given A :: Compare
|
||||||
instance Eq[A, A]
|
instance Eq A A
|
||||||
fn eq: (x: A, y: A) => Boolean
|
fn eq: A -> A -> Boolean
|
||||||
match compare(x, y)
|
λ x y =>
|
||||||
|
match compare x y
|
||||||
case EqualTo => true
|
case EqualTo => true
|
||||||
case _ => false
|
case _ => false
|
||||||
|
end match
|
||||||
end fn
|
end fn
|
||||||
end instance
|
end instance
|
||||||
|
|
||||||
given A
|
given A
|
||||||
class HashCode
|
class HashCode
|
||||||
fn hash_code(data: A) => Int32
|
fn hash_code: A -> Int32
|
||||||
end class
|
end class
|
||||||
```
|
```
|
||||||
|
|
|
@ -7,10 +7,10 @@ but records have named parameters.
|
||||||
## Syntax
|
## Syntax
|
||||||
|
|
||||||
```
|
```
|
||||||
let x := ()
|
let x := #()
|
||||||
let y := ("foo")
|
let y := #("foo")
|
||||||
let z := ("foo", 1)
|
let z := #("foo", 1)
|
||||||
let w := ("foo", 1, true, 3.14)
|
let w := #("foo", 1, true, 3.14)
|
||||||
```
|
```
|
||||||
|
|
||||||
## Type of a Standard Tuple
|
## Type of a Standard Tuple
|
||||||
|
|
Loading…
Add table
Reference in a new issue