Big changes/progress, functions are finally becoming decent.

This commit is contained in:
Pat Garrity 2024-02-07 06:50:42 -06:00
parent 2ad400167a
commit 6a08ad31f0
Signed by: pfm
GPG key ID: 5CA5D21BAB7F3A76
7 changed files with 127 additions and 114 deletions

View file

@ -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 *)
(* ===== *)

View file

@ -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
```
```

View file

@ -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
```

View file

@ -12,7 +12,6 @@ Names are UTF-8 strings. The following values are _excluded_:
- `"`
- `,`
- `\`
- `[` or `]`
- `(` or `)`
## Convention

View file

@ -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
```

View file

@ -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
```

View file

@ -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