Skip to content

Commit

Permalink
Merge #715
Browse files Browse the repository at this point in the history
715: Document gadt r=Marwes a=Marwes



Co-authored-by: Markus Westerlind <marwes91@gmail.com>
  • Loading branch information
bors[bot] and Marwes committed Apr 16, 2019
2 parents 3c3dbd6 + d3f48b8 commit a17fe11
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 16 deletions.
41 changes: 40 additions & 1 deletion book/src/syntax-and-semantics.md
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,7 @@ f { x = 1, y = 2, other = "abc" } // The record we pass can hold more fields tha

[Row type]:./syntax-and-semantics.html#row-type

### Enumeration type
### Variant type

```
( | <identifier> (<type>)* )*
Expand All @@ -449,6 +449,45 @@ f { x = 1, y = 2, other = "abc" } // The record we pass can hold more fields tha

Gluon also has a second way of grouping data which is the enumeration type which allows you to represent a value being one of several variants. In the example above is the representation of Gluon's standard `Result` type. It represents either the value having been successfully computed (`Ok t`) or that an error occurred (`Err e`).

#### Generalized algebraic data type

Variants also have an alternate syntax which allows [Generalized Algebraic Data Type][GADT] (GADT) to be specified.

```
type <identifier> (<identifier>)* = ( | <identifier> : (<type>)* )*
type Result e t =
| Err : e -> Result e t
| Ok : t -> Result e t
```

This encodes the same type as the variant in the previous (with the restriction that the variant must be specified as the top of the type definition).
While this simple example doesn't do anything that a normal variant could not define it is possible to encode much more information about what a variant contains through such as the canonical expression example.

```f#,rust
type Expr a =
| Int : Int -> Expr Int
| Bool : Bool -> Expr Bool
| Add : Expr Int -> Expr Int -> Expr Int
| If : Expr Bool -> Expr a -> Expr a -> Expr a
let eval e : Expr a -> a =
match e with
| Int x -> x
| Bool x -> x
| Add l r -> eval l + eval r
| If p t f -> if eval p then eval t else eval f
let int : Int = eval (If (Bool True) (Add (Int 1) (Int 2)) (Int 0))
let bool : Bool = eval (Bool True)
()
```

Through specifying a more specific type in the return type of a GADT variant we enforce that the variant can only contain that specific type
in the argument. We can then exploit it when matching to refine the argument.

[GADT]:https://en.wikipedia.org/wiki/Generalized_algebraic_data_type

### Alias type

```
Expand Down
52 changes: 41 additions & 11 deletions examples/lisp/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,21 @@ extern crate gluon_codegen;

use std::io::{self, BufRead};

use gluon::vm::api::{FunctionRef, OpaqueValue};
use gluon::{new_vm, Compiler, RootedThread};
use gluon::{
new_vm,
vm::api::{FunctionRef, OpaqueValue},
Compiler, RootedThread,
};

#[derive(VmType)]
#[gluon(vm_type = "examples.lisp.lisp.Expr")]
struct Expr;
type OpaqueExpr = OpaqueValue<RootedThread, Expr>;
struct ExprMarker;
type Expr = OpaqueValue<RootedThread, ExprMarker>;

#[derive(VmType)]
#[gluon(vm_type = "examples.lisp.lisp.LispState")]
struct LispState;
type OpaqueLispState = OpaqueValue<RootedThread, LispState>;
struct LispStateMarker;
type LispState = OpaqueValue<RootedThread, LispStateMarker>;

fn main() {
if let Err(err) = main_() {
Expand All @@ -31,14 +34,13 @@ fn main_() -> gluon::Result<()> {
let thread = new_vm();
Compiler::new().load_file(&thread, "examples/lisp/lisp.glu")?;

let mut eval: FunctionRef<
fn(String, OpaqueLispState) -> Result<(OpaqueExpr, OpaqueLispState), String>,
> = thread.get_global("examples.lisp.lisp.eval_env_string")?;
let mut eval: FunctionRef<fn(String, LispState) -> Result<(Expr, LispState), String>> =
thread.get_global("examples.lisp.lisp.eval_env_string")?;

let mut show: FunctionRef<fn(OpaqueExpr) -> String> =
let mut show: FunctionRef<fn(Expr) -> String> =
thread.get_global("examples.lisp.lisp.show.show")?;

let mut env: OpaqueLispState = thread.get_global("examples.lisp.lisp.default_env")?;
let mut env: LispState = thread.get_global("examples.lisp.lisp.default_env")?;

let stdin = io::stdin();
for line in stdin.lock().lines() {
Expand All @@ -55,3 +57,31 @@ fn main_() -> gluon::Result<()> {
}
Ok(())
}

#[cfg(test)]
mod tests {
use super::*;

use gluon::Error;

fn eval_lisp(expr: &str) -> Result<String, Error> {
let thread = new_vm();
Compiler::new().load_file(&thread, "examples/lisp/lisp.glu")?;

let mut eval: FunctionRef<fn(String, LispState) -> Result<(Expr, LispState), String>> =
thread.get_global("examples.lisp.lisp.eval_env_string")?;

let mut show: FunctionRef<fn(Expr) -> String> =
thread.get_global("examples.lisp.lisp.show.show")?;

let env: LispState = thread.get_global("examples.lisp.lisp.default_env")?;

let (msg, _) = eval.call(expr.to_string(), env.clone())??;
Ok(show.call(msg.clone())?)
}

#[test]
fn basic() {
assert_eq!(eval_lisp("(+ 1 2 3)").unwrap(), "6");
}
}
7 changes: 3 additions & 4 deletions repl/src/repl.glu
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ let { flat_map, (>>=) } = import! std.monad
let { foldl } = import! std.foldable

let { (<>) } = import! std.prelude
let (++) = (<>)

rec
type ReplEffect r a = [| reader : Reader Repl, state : State Settings, lift : Lift IO | r |] a
Expand Down Expand Up @@ -139,7 +138,7 @@ let commands : Commands =
alias = "p",
info = "Sets the prompt",
action = \prompt ->
do _ = modify (\settings ->
seq modify (\settings ->
// TODO Should be able infer this before the `..` splatting
let settings : Settings = settings
{ prompt,
Expand All @@ -150,9 +149,9 @@ let commands : Commands =
{
name = "color",
alias = "c",
info = "Sets wheter to use color in the repl: auto, always, always-ansi, never",
info = "Sets whether to use color in the repl: auto, always, always-ansi, never",
action = \color ->
do _ =
seq
match repl_prim.parse_color color with
| Ok color ->
modify (\settings ->
Expand Down

0 comments on commit a17fe11

Please sign in to comment.