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

View file

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

View file

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

View file

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

View file

@ -5,7 +5,7 @@ records are just [tuples](tuples.md) with named fields. In many ways, the two
can be interchanged. can be interchanged.
``` ```
record Foo (x: String, y: Int32) record Foo(x: String, y: Int32)
``` ```
Record fields are both _ordered_ and _named_. 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. Records do _not_ need to be named.
``` ```
(x: String, y: String, z: String) #(x: String, y: String, z: String)
``` ```
## Generic Records ## Generic Records
@ -32,7 +32,7 @@ Records may have generically typed data, and accept a type constructor:
``` ```
given A, B given A, B
record Foo (x: A, y: B) record Foo(x: A, y: B)
``` ```
## Instantiating Records ## Instantiating 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
@ -50,11 +53,11 @@ Copy syntax allows any record to be duplicated, with any fields explicitly
overridden by some value: 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
@ -62,7 +65,7 @@ let baz := copy(foo, ("y": 2))
The `.` operator is used to access individual fields on a record. 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 foo := Foo("foo", 1)
let bar := foo.x let bar := foo.x
@ -75,45 +78,43 @@ Tuple syntax is _not_ supported on records.
Use the following record definition for this section: 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. 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
```

View file

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

View file

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