extend unique List api

This commit is contained in:
Folkert 2020-02-29 22:44:51 +01:00
parent af3fc03c26
commit 33d5c2c0e2
4 changed files with 221 additions and 21 deletions

View File

@ -605,7 +605,11 @@ define_builtins! {
2 LIST_ISEMPTY: "isEmpty"
3 LIST_GET: "get"
4 LIST_SET: "set"
5 LIST_MAP: "map"
5 LIST_PUSH: "push"
6 LIST_MAP: "map"
7 LIST_LENGTH: "length"
8 LIST_FOLDL: "foldl"
9 LIST_FOLDR: "foldr"
}
7 RESULT: "Result" => {
0 RESULT_RESULT: "Result" imported // the Result.Result type alias

View File

@ -417,7 +417,11 @@ impl Type {
}
ext.instantiate_aliases(aliases, var_store, introduced);
}
Alias(_, _, actual_type) => {
Alias(_, type_args, actual_type) => {
for arg in type_args {
arg.1.instantiate_aliases(aliases, var_store, introduced);
}
actual_type.instantiate_aliases(aliases, var_store, introduced);
}
Apply(symbol, args) => {

View File

@ -4,7 +4,7 @@ use crate::can::ident::TagName;
use crate::collections::{default_hasher, MutMap};
use crate::module::symbol::Symbol;
use crate::region::{Located, Region};
use crate::solve::{BuiltinAlias, SolvedType};
use crate::solve::{BuiltinAlias, SolvedAtom, SolvedType};
use crate::subs::VarId;
use std::collections::HashMap;
@ -22,6 +22,21 @@ const UVAR1: VarId = VarId::from_u32(1001);
const UVAR2: VarId = VarId::from_u32(1002);
const UVAR3: VarId = VarId::from_u32(1003);
const UVAR4: VarId = VarId::from_u32(1004);
const UVAR5: VarId = VarId::from_u32(1005);
fn shared() -> SolvedType {
SolvedType::Boolean(SolvedAtom::Zero, vec![])
}
fn boolean(b: VarId) -> SolvedType {
SolvedType::Boolean(SolvedAtom::Variable(b), vec![])
}
fn disjunction(free: VarId, rest: Vec<VarId>) -> SolvedType {
let solved_rest = rest.into_iter().map(SolvedAtom::Variable).collect();
SolvedType::Boolean(SolvedAtom::Variable(free), solved_rest)
}
pub fn uniqueness_stdlib() -> StdLib {
use builtins::Mode;
@ -161,6 +176,16 @@ pub fn aliases() -> MutMap<Symbol, BuiltinAlias> {
},
);
// Str : [ @Str ]
add_alias(
Symbol::STR_STR,
BuiltinAlias {
region: Region::zero(),
vars: Vec::new(),
typ: single_private_tag(Symbol::STR_AT_STR, Vec::new()),
},
);
aliases
}
@ -258,6 +283,12 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
unique_function(vec![list_type(UVAR1, TVAR1)], bool_type(UVAR2)),
);
// length : List a -> Int
add_type(
Symbol::LIST_LENGTH,
unique_function(vec![list_type(UVAR1, TVAR1)], int_type(UVAR2)),
);
// get : List a, Int -> Result a [ IndexOutOfBounds ]*
let index_out_of_bounds = SolvedType::TagUnion(
vec![(TagName::Global("IndexOutOfBounds".into()), vec![])],
@ -272,12 +303,107 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
),
);
// set : List a, Int, a -> List a
add_type(
Symbol::LIST_SET,
// set : Attr (w | u | v) (List (Attr u a))
// , Attr * Int
// , Attr (u | v) a
// -> List a
add_type(Symbol::LIST_SET, {
let u = UVAR1;
let v = UVAR2;
let w = UVAR3;
let star1 = UVAR4;
let star2 = UVAR5;
let a = TVAR1;
unique_function(
vec![list_type(UVAR1, TVAR1), int_type(UVAR2), flex(TVAR1)],
list_type(UVAR3, TVAR1),
vec![
SolvedType::Apply(
Symbol::ATTR_ATTR,
vec![
disjunction(w, vec![u, v]),
SolvedType::Apply(Symbol::LIST_LIST, vec![attr_type(u, a)]),
],
),
int_type(star1),
SolvedType::Apply(Symbol::ATTR_ATTR, vec![disjunction(u, vec![v]), flex(a)]),
],
SolvedType::Apply(
Symbol::ATTR_ATTR,
vec![
boolean(star2),
SolvedType::Apply(Symbol::LIST_LIST, vec![attr_type(u, a)]),
],
),
)
});
// push : Attr (w | u | v) (List (Attr u a))
// , Attr (u | v) a
// -> Attr * (List (Attr u a))
add_type(Symbol::LIST_PUSH, {
let u = UVAR1;
let v = UVAR2;
let w = UVAR3;
let star = UVAR4;
let a = TVAR1;
unique_function(
vec![
SolvedType::Apply(
Symbol::ATTR_ATTR,
vec![
disjunction(w, vec![u, v]),
SolvedType::Apply(Symbol::LIST_LIST, vec![attr_type(u, a)]),
],
),
SolvedType::Apply(Symbol::ATTR_ATTR, vec![disjunction(u, vec![v]), flex(a)]),
],
SolvedType::Apply(
Symbol::ATTR_ATTR,
vec![
boolean(star),
SolvedType::Apply(Symbol::LIST_LIST, vec![attr_type(u, a)]),
],
),
)
});
// map : List a, (a -> b) -> List b
add_type(
Symbol::LIST_MAP,
unique_function(
vec![
list_type(UVAR1, TVAR1),
SolvedType::Apply(
Symbol::ATTR_ATTR,
vec![
shared(),
SolvedType::Func(vec![flex(TVAR1)], Box::new(flex(TVAR2))),
],
),
],
list_type(UVAR2, TVAR2),
),
);
// foldr : List a, (a -> b -> b), b -> b
add_type(
Symbol::LIST_FOLDR,
unique_function(
vec![
list_type(UVAR1, TVAR1),
SolvedType::Apply(
Symbol::ATTR_ATTR,
vec![
shared(),
SolvedType::Func(vec![flex(TVAR1), flex(TVAR2)], Box::new(flex(TVAR2))),
],
),
flex(TVAR2),
],
flex(TVAR2),
),
);

View File

@ -1890,19 +1890,6 @@ mod test_infer_uniq {
);
}
#[test]
fn list_set() {
infer_eq(
indoc!(
r#"
[1, 2 ]
|> List.set 1 42
"#
),
"Attr * (List (Attr * Int))",
);
}
#[test]
fn float_div_builtins() {
infer_eq(
@ -2024,4 +2011,83 @@ mod test_infer_uniq {
"Attr * (Attr (a | b) (List (Attr a Int)) -> Attr (a | b) (List (Attr a Int)))",
);
}
#[test]
fn list_set() {
infer_eq(indoc!(r#"List.set"#), "Attr * (Attr (* | a | b) (List (Attr b c)), Attr * Int, Attr (a | b) c -> Attr * (List (Attr b c)))");
}
#[test]
fn list_map() {
infer_eq(
indoc!(r#"List.map"#),
"Attr * (Attr * (List a), Attr Shared (a -> b) -> Attr * (List b))",
);
}
#[test]
fn list_map_identity() {
infer_eq(
indoc!(r#"\list -> List.map list (\x -> x)"#),
"Attr * (Attr * (List a) -> Attr * (List a))",
);
}
#[test]
fn list_foldr() {
infer_eq(
indoc!(r#"List.foldr"#),
"Attr * (Attr * (List a), Attr Shared (a, b -> b), b -> b)",
);
}
#[test]
fn list_foldr_sum() {
infer_eq(
indoc!(
r#"
sum = \list -> List.foldr list Num.add 0
sum
"#
),
"Attr * (Attr * (List (Attr * Int)) -> Attr * Int)",
);
}
#[test]
fn list_push() {
infer_eq(
indoc!(r#"List.push"#),
"Attr * (Attr (* | a | b) (List (Attr b c)), Attr (a | b) c -> Attr * (List (Attr b c)))"
);
}
#[test]
fn list_push_singleton() {
infer_eq(
indoc!(
r#"
singleton = \x -> List.push [] x
singleton
"#
),
"Attr * (Attr (* | a) b -> Attr * (List (Attr a b)))",
);
}
#[test]
fn list_foldr_reverse() {
infer_eq(
indoc!(
r#"
reverse = \list -> List.foldr list (\e, l -> List.push l e) []
reverse
"#
),
"Attr * (Attr * (List (Attr (a | b) c)) -> Attr (* | a | b) (List (Attr a c)))",
);
}
}