mirror of
https://github.com/roc-lang/roc.git
synced 2025-11-02 05:48:17 +00:00
Move Eq to Bool
This commit is contained in:
parent
bd5f5ed735
commit
a256947a9f
19 changed files with 92 additions and 101 deletions
|
|
@ -1,8 +1,34 @@
|
|||
interface Bool
|
||||
exposes [Bool, true, false, and, or, not, isNotEq]
|
||||
exposes [Bool, Eq, true, false, and, or, not, isEq, isNotEq, structuralEq]
|
||||
imports []
|
||||
|
||||
Bool := [True, False]
|
||||
## A type that can be compared for total equality.
|
||||
##
|
||||
## Total equality means that all values of the type can be compared to each
|
||||
## other, and two values `a`, `b` are identical if and only if `isEq a b` is
|
||||
## `Bool.true`.
|
||||
##
|
||||
## Not all types support total equality. For example, an [F32] or [F64] can
|
||||
## be a `NaN` ([not a number](https://en.wikipedia.org/wiki/NaN)), and the [IEEE-754](https://en.wikipedia.org/wiki/IEEE_754)
|
||||
## floating point standard specifies that two `NaN`s are never equal to each other.
|
||||
Eq has
|
||||
## Returns `Bool.true` if the two values are equal, and `Bool.false` otherwise.
|
||||
##
|
||||
## `a == b` is shorthand for `Eq.isEq a b`.
|
||||
##
|
||||
## When `isEq` is derived by the Roc compiler, values are compared via
|
||||
## structural equality. Structural equality works as follows:
|
||||
##
|
||||
## 1. Tags are equal if they have the same tag name, and also their contents (if any) are equal.
|
||||
## 2. Records are equal if all their fields are equal.
|
||||
## 3. Collections ([Str], [List], [Dict], and [Set]) are equal if they are the same length, and also all their corresponding elements are equal.
|
||||
## 4. [Num](Num#Num) values are equal if their numbers are equal, with one exception: if both arguments to `isEq` are *NaN*, then `isEq` returns `Bool.false`. See `Num.isNaN` for more about *NaN*.
|
||||
## 5. Functions can never be compared for structural equality. Roc cannot derive `isEq` for types that contain functions!
|
||||
isEq : a, a -> Bool | a has Eq
|
||||
|
||||
Bool := [True, False] has [Eq {isEq: boolIsEq}]
|
||||
|
||||
boolIsEq = \@Bool b1, @Bool b2 -> structuralEq b1 b2
|
||||
|
||||
## The boolean true value.
|
||||
true : Bool
|
||||
|
|
@ -74,3 +100,13 @@ not : Bool -> Bool
|
|||
## Note that `isNotEq` takes `'val` instead of `val`, which means `isNotEq` does not
|
||||
## accept arguments whose types contain functions.
|
||||
isNotEq : a, a -> Bool
|
||||
|
||||
# ## Calls [isEq] on the given values, then calls [not] on the result.
|
||||
# ##
|
||||
# ## `a != b` is shorthand for `Eq.isNotEq a b`.
|
||||
# isNotEq : a, a -> Bool | a has Eq
|
||||
# isNotEq = \a, b -> Bool.not (isEq a b)
|
||||
|
||||
# INTERNAL COMPILER USE ONLY: used to lower calls to `isEq` to structural
|
||||
# equality via the `Eq` low-level for derived types.
|
||||
structuralEq : a, a -> Bool
|
||||
|
|
|
|||
|
|
@ -18,8 +18,7 @@ interface Dict
|
|||
removeAll,
|
||||
]
|
||||
imports [
|
||||
Bool.{ Bool },
|
||||
Eq.{ Eq },
|
||||
Bool.{ Bool, Eq },
|
||||
Result.{ Result },
|
||||
List,
|
||||
Num.{ Nat },
|
||||
|
|
|
|||
|
|
@ -1,44 +0,0 @@
|
|||
interface Eq
|
||||
exposes [
|
||||
Eq,
|
||||
isEq,
|
||||
isNotEq,
|
||||
structuralEq,
|
||||
]
|
||||
imports [
|
||||
Bool.{ Bool },
|
||||
]
|
||||
|
||||
## A type that can be compared for total equality.
|
||||
##
|
||||
## Total equality means that all values of the type can be compared to each
|
||||
## other, and two values `a`, `b` are identical if and only if `isEq a b` is
|
||||
## `Bool.true`.
|
||||
##
|
||||
## Not all types support total equality. For example, an [F32] or [F64] can
|
||||
## be a `NaN` ([not a number](https://en.wikipedia.org/wiki/NaN)), and the [IEEE-754](https://en.wikipedia.org/wiki/IEEE_754)
|
||||
## floating point standard specifies that two `NaN`s are never equal to each other.
|
||||
Eq has
|
||||
## Returns `Bool.true` if the two values are equal, and `Bool.false` otherwise.
|
||||
##
|
||||
## `a == b` is shorthand for `Eq.isEq a b`.
|
||||
##
|
||||
## When `isEq` is derived by the Roc compiler, values are compared via
|
||||
## structural equality. Structural equality works as follows:
|
||||
##
|
||||
## 1. Tags are equal if they have the same tag name, and also their contents (if any) are equal.
|
||||
## 2. Records are equal if all their fields are equal.
|
||||
## 3. Collections ([Str], [List], [Dict], and [Set]) are equal if they are the same length, and also all their corresponding elements are equal.
|
||||
## 4. [Num](Num#Num) values are equal if their numbers are equal, with one exception: if both arguments to `isEq` are *NaN*, then `isEq` returns `Bool.false`. See `Num.isNaN` for more about *NaN*.
|
||||
## 5. Functions can never be compared for structural equality. Roc cannot derive `isEq` for types that contain functions!
|
||||
isEq : a, a -> Bool | a has Eq
|
||||
|
||||
## Calls [isEq] on the given values, then calls [not] on the result.
|
||||
##
|
||||
## `a != b` is shorthand for `Eq.isNotEq a b`.
|
||||
isNotEq : a, a -> Bool | a has Eq
|
||||
isNotEq = \a, b -> Bool.not (isEq a b)
|
||||
|
||||
# INTERNAL COMPILER USE ONLY: used to lower calls to `isEq` to structural
|
||||
# equality via the `Eq` low-level for derived types.
|
||||
structuralEq : a, a -> Bool
|
||||
|
|
@ -33,8 +33,7 @@ interface Json
|
|||
F64,
|
||||
Dec,
|
||||
},
|
||||
Bool.{ Bool },
|
||||
Eq.{ Eq },
|
||||
Bool.{ Bool, Eq },
|
||||
Result,
|
||||
]
|
||||
|
||||
|
|
|
|||
|
|
@ -65,8 +65,7 @@ interface List
|
|||
countIf,
|
||||
]
|
||||
imports [
|
||||
Bool.{ Bool },
|
||||
Eq.{ Eq },
|
||||
Bool.{ Bool, Eq },
|
||||
Result.{ Result },
|
||||
Num.{ Nat, Num, Int },
|
||||
]
|
||||
|
|
|
|||
|
|
@ -146,7 +146,6 @@ interface Num
|
|||
imports [
|
||||
Bool.{ Bool },
|
||||
Result.{ Result },
|
||||
Eq,
|
||||
]
|
||||
|
||||
## Represents a number that could be either an [Int] or a [Frac].
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ interface Set
|
|||
intersection,
|
||||
difference,
|
||||
]
|
||||
imports [List, Bool.{ Bool }, Eq.{ Eq }, Dict.{ Dict }, Num.{ Nat }]
|
||||
imports [List, Bool.{ Bool, Eq }, Dict.{ Dict }, Num.{ Nat }]
|
||||
|
||||
Set k := Dict.Dict k {} has [Eq { isEq: setEq }]
|
||||
|
||||
|
|
|
|||
|
|
@ -47,8 +47,7 @@ interface Str
|
|||
withPrefix,
|
||||
]
|
||||
imports [
|
||||
Bool.{ Bool },
|
||||
Eq.{ Eq },
|
||||
Bool.{ Bool, Eq },
|
||||
Result.{ Result },
|
||||
List,
|
||||
Num.{ Nat, Num, U8, U16, U32, U64, U128, I8, I16, I32, I64, I128, F32, F64, Dec },
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ pub fn module_source(module_id: ModuleId) -> &'static str {
|
|||
ModuleId::ENCODE => ENCODE,
|
||||
ModuleId::DECODE => DECODE,
|
||||
ModuleId::HASH => HASH,
|
||||
ModuleId::EQ => EQ,
|
||||
ModuleId::JSON => JSON,
|
||||
_ => panic!(
|
||||
"ModuleId {:?} is not part of the standard library",
|
||||
|
|
@ -34,5 +33,4 @@ const BOOL: &str = include_str!("../roc/Bool.roc");
|
|||
const ENCODE: &str = include_str!("../roc/Encode.roc");
|
||||
const DECODE: &str = include_str!("../roc/Decode.roc");
|
||||
const HASH: &str = include_str!("../roc/Hash.roc");
|
||||
const EQ: &str = include_str!("../roc/Eq.roc");
|
||||
const JSON: &str = include_str!("../roc/Json.roc");
|
||||
|
|
|
|||
|
|
@ -192,7 +192,6 @@ map_symbol_to_lowlevel_and_arity! {
|
|||
NumShiftRightZfBy; NUM_SHIFT_RIGHT_ZERO_FILL; 2,
|
||||
NumToStr; NUM_TO_STR; 1,
|
||||
|
||||
Eq; BOOL_EQ; 2,
|
||||
Eq; EQ_STRUCTURAL_EQ; 2,
|
||||
NotEq; BOOL_NEQ; 2,
|
||||
And; BOOL_AND; 2,
|
||||
|
|
|
|||
|
|
@ -409,7 +409,7 @@ fn binop_to_function(binop: BinOp) -> (&'static str, &'static str) {
|
|||
Percent => (ModuleName::NUM, "rem"),
|
||||
Plus => (ModuleName::NUM, "add"),
|
||||
Minus => (ModuleName::NUM, "sub"),
|
||||
Equals => (ModuleName::EQ, "isEq"),
|
||||
Equals => (ModuleName::BOOL, "isEq"),
|
||||
NotEquals => (ModuleName::BOOL, "isNotEq"),
|
||||
LessThan => (ModuleName::NUM, "isLt"),
|
||||
GreaterThan => (ModuleName::NUM, "isGt"),
|
||||
|
|
|
|||
|
|
@ -178,7 +178,6 @@ impl Default for ModuleCache<'_> {
|
|||
ENCODE,
|
||||
DECODE,
|
||||
HASH,
|
||||
EQ,
|
||||
JSON,
|
||||
}
|
||||
|
||||
|
|
@ -2248,7 +2247,6 @@ fn update<'a>(
|
|||
extend_header_with_builtin(&mut header, ModuleId::ENCODE);
|
||||
extend_header_with_builtin(&mut header, ModuleId::DECODE);
|
||||
extend_header_with_builtin(&mut header, ModuleId::HASH);
|
||||
extend_header_with_builtin(&mut header, ModuleId::EQ);
|
||||
}
|
||||
|
||||
state
|
||||
|
|
@ -3283,7 +3281,6 @@ fn load_module<'a>(
|
|||
"Encode", ModuleId::ENCODE
|
||||
"Decode", ModuleId::DECODE
|
||||
"Hash", ModuleId::HASH
|
||||
"Eq", ModuleId::EQ
|
||||
"Json", ModuleId::JSON
|
||||
}
|
||||
|
||||
|
|
@ -4781,7 +4778,6 @@ fn canonicalize_and_constrain<'a>(
|
|||
| ModuleId::DICT
|
||||
| ModuleId::SET
|
||||
| ModuleId::HASH
|
||||
| ModuleId::EQ
|
||||
);
|
||||
|
||||
if !name.is_builtin() || should_include_builtin {
|
||||
|
|
|
|||
|
|
@ -86,7 +86,6 @@ impl ModuleName {
|
|||
pub const ENCODE: &'static str = "Encode";
|
||||
pub const DECODE: &'static str = "Decode";
|
||||
pub const HASH: &'static str = "Hash";
|
||||
pub const EQ: &'static str = "Eq";
|
||||
pub const JSON: &'static str = "Json";
|
||||
|
||||
pub fn as_str(&self) -> &str {
|
||||
|
|
|
|||
|
|
@ -184,7 +184,6 @@ macro_rules! map_symbol_to_lowlevel {
|
|||
// Below, we explicitly handle some exceptions to the pattern where a lowlevel maps
|
||||
// directly to a symbol. If you are unsure if your lowlevel is an exception, assume
|
||||
// that it isn't and just see if that works.
|
||||
#[allow(unreachable_patterns)] // TODO: remove after we replace `BOOL_EQ` with `EQ_EQ` wholly
|
||||
match lowlevel {
|
||||
$(
|
||||
LowLevel::$lowlevel => Symbol::$symbol,
|
||||
|
|
@ -310,7 +309,6 @@ map_symbol_to_lowlevel! {
|
|||
NumShiftRightBy <= NUM_SHIFT_RIGHT,
|
||||
NumShiftRightZfBy <= NUM_SHIFT_RIGHT_ZERO_FILL,
|
||||
NumToStr <= NUM_TO_STR,
|
||||
Eq <= BOOL_EQ,
|
||||
Eq <= EQ_STRUCTURAL_EQ,
|
||||
NotEq <= BOOL_NEQ,
|
||||
And <= BOOL_AND,
|
||||
|
|
|
|||
|
|
@ -1251,8 +1251,11 @@ define_builtins! {
|
|||
4 BOOL_OR: "or"
|
||||
5 BOOL_NOT: "not"
|
||||
6 BOOL_XOR: "xor"
|
||||
7 BOOL_EQ: "isEq"
|
||||
8 BOOL_NEQ: "isNotEq"
|
||||
7 BOOL_NEQ: "isNotEq"
|
||||
8 EQ_EQ: "Eq" exposed_type=true
|
||||
9 EQ_IS_EQ: "isEq"
|
||||
10 EQ_STRUCTURAL_EQ: "structuralEq"
|
||||
11 BOOL_IS_EQ_IMPL: "boolIsEq"
|
||||
}
|
||||
5 STR: "Str" => {
|
||||
0 STR_STR: "Str" exposed_apply_type=true // the Str.Str type alias
|
||||
|
|
@ -1525,15 +1528,9 @@ define_builtins! {
|
|||
15 HASH_HASH_STR_BYTES: "hashStrBytes"
|
||||
16 HASH_HASH_LIST: "hashList"
|
||||
}
|
||||
14 EQ: "Eq" => {
|
||||
0 EQ_EQ: "Eq" exposed_type=true
|
||||
1 EQ_IS_EQ: "isEq"
|
||||
2 EQ_IS_NOT_EQ: "isNotEq"
|
||||
3 EQ_STRUCTURAL_EQ: "structuralEq"
|
||||
}
|
||||
15 JSON: "Json" => {
|
||||
14 JSON: "Json" => {
|
||||
0 JSON_JSON: "Json"
|
||||
}
|
||||
|
||||
num_modules: 16 // Keep this count up to date by hand! (TODO: see the mut_map! macro for how we could determine this count correctly in the macro)
|
||||
num_modules: 15 // Keep this count up to date by hand! (TODO: see the mut_map! macro for how we could determine this count correctly in the macro)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -378,6 +378,7 @@ mod solve_expr {
|
|||
let known_specializations = abilities_store.iter_declared_implementations().filter_map(
|
||||
|(impl_key, member_impl)| match member_impl {
|
||||
MemberImpl::Impl(impl_symbol) => {
|
||||
dbg!(impl_symbol);
|
||||
let specialization = abilities_store.specialization_info(*impl_symbol).expect(
|
||||
"declared implementations should be resolved conclusively after solving",
|
||||
);
|
||||
|
|
@ -7984,7 +7985,7 @@ mod solve_expr {
|
|||
|
||||
isEq = \@Trivial {}, @Trivial {} -> Bool.true
|
||||
|
||||
main = Eq.isEq (@Trivial {}) (@Trivial {})
|
||||
main = Bool.isEq (@Trivial {}) (@Trivial {})
|
||||
"#
|
||||
),
|
||||
"Bool",
|
||||
|
|
|
|||
|
|
@ -13,26 +13,42 @@ use roc_derive_key::DeriveBuiltin::IsEq;
|
|||
#[test]
|
||||
fn immediates() {
|
||||
// Everything is an immediate for `Eq`.
|
||||
check_single_lset_immediate(IsEq, v!(U8), Symbol::BOOL_EQ);
|
||||
check_single_lset_immediate(IsEq, v!(U16), Symbol::BOOL_EQ);
|
||||
check_single_lset_immediate(IsEq, v!(U32), Symbol::BOOL_EQ);
|
||||
check_single_lset_immediate(IsEq, v!(U64), Symbol::BOOL_EQ);
|
||||
check_single_lset_immediate(IsEq, v!(U128), Symbol::BOOL_EQ);
|
||||
check_single_lset_immediate(IsEq, v!(I8), Symbol::BOOL_EQ);
|
||||
check_single_lset_immediate(IsEq, v!(I16), Symbol::BOOL_EQ);
|
||||
check_single_lset_immediate(IsEq, v!(I32), Symbol::BOOL_EQ);
|
||||
check_single_lset_immediate(IsEq, v!(I64), Symbol::BOOL_EQ);
|
||||
check_single_lset_immediate(IsEq, v!(I128), Symbol::BOOL_EQ);
|
||||
check_single_lset_immediate(IsEq, v!(STR), Symbol::BOOL_EQ);
|
||||
check_single_lset_immediate(IsEq, v!(Symbol::LIST_LIST v!(U8)), Symbol::BOOL_EQ);
|
||||
check_single_lset_immediate(IsEq, v!(Symbol::LIST_LIST v!(STR)), Symbol::BOOL_EQ);
|
||||
check_single_lset_immediate(IsEq, v!({ a: v!(U8), }), Symbol::BOOL_EQ);
|
||||
check_single_lset_immediate(IsEq, v!(EMPTY_RECORD), Symbol::BOOL_EQ);
|
||||
check_single_lset_immediate(IsEq, v!([ A v!(U8) v!(STR), B v!(STR) ]), Symbol::BOOL_EQ);
|
||||
check_single_lset_immediate(IsEq, v!([ A v!(U8) v!(STR), B v!(STR) ]), Symbol::BOOL_EQ);
|
||||
check_single_lset_immediate(IsEq, v!([ Nil, Cons v!(^lst)] as lst), Symbol::BOOL_EQ);
|
||||
check_single_lset_immediate(IsEq, v!(U8), Symbol::EQ_STRUCTURAL_EQ);
|
||||
check_single_lset_immediate(IsEq, v!(U16), Symbol::EQ_STRUCTURAL_EQ);
|
||||
check_single_lset_immediate(IsEq, v!(U32), Symbol::EQ_STRUCTURAL_EQ);
|
||||
check_single_lset_immediate(IsEq, v!(U64), Symbol::EQ_STRUCTURAL_EQ);
|
||||
check_single_lset_immediate(IsEq, v!(U128), Symbol::EQ_STRUCTURAL_EQ);
|
||||
check_single_lset_immediate(IsEq, v!(I8), Symbol::EQ_STRUCTURAL_EQ);
|
||||
check_single_lset_immediate(IsEq, v!(I16), Symbol::EQ_STRUCTURAL_EQ);
|
||||
check_single_lset_immediate(IsEq, v!(I32), Symbol::EQ_STRUCTURAL_EQ);
|
||||
check_single_lset_immediate(IsEq, v!(I64), Symbol::EQ_STRUCTURAL_EQ);
|
||||
check_single_lset_immediate(IsEq, v!(I128), Symbol::EQ_STRUCTURAL_EQ);
|
||||
check_single_lset_immediate(IsEq, v!(STR), Symbol::EQ_STRUCTURAL_EQ);
|
||||
check_single_lset_immediate(IsEq, v!(Symbol::LIST_LIST v!(U8)), Symbol::EQ_STRUCTURAL_EQ);
|
||||
check_single_lset_immediate(
|
||||
IsEq,
|
||||
v!(Symbol::LIST_LIST v!(STR)),
|
||||
Symbol::EQ_STRUCTURAL_EQ,
|
||||
);
|
||||
check_single_lset_immediate(IsEq, v!({ a: v!(U8), }), Symbol::EQ_STRUCTURAL_EQ);
|
||||
check_single_lset_immediate(IsEq, v!(EMPTY_RECORD), Symbol::EQ_STRUCTURAL_EQ);
|
||||
check_single_lset_immediate(
|
||||
IsEq,
|
||||
v!([ A v!(U8) v!(STR), B v!(STR) ]),
|
||||
Symbol::EQ_STRUCTURAL_EQ,
|
||||
);
|
||||
check_single_lset_immediate(
|
||||
IsEq,
|
||||
v!([ A v!(U8) v!(STR), B v!(STR) ]),
|
||||
Symbol::EQ_STRUCTURAL_EQ,
|
||||
);
|
||||
check_single_lset_immediate(
|
||||
IsEq,
|
||||
v!([ Nil, Cons v!(^lst)] as lst),
|
||||
Symbol::EQ_STRUCTURAL_EQ,
|
||||
);
|
||||
|
||||
// NOTE: despite this reaching an immediate, `F64`s will never actually be allowed to be
|
||||
// compared, because obligation checking will rule them out from `isEq`!
|
||||
check_single_lset_immediate(IsEq, v!(F64), Symbol::BOOL_EQ);
|
||||
check_single_lset_immediate(IsEq, v!(F64), Symbol::EQ_STRUCTURAL_EQ);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,8 +56,8 @@ fn module_source_and_path(builtin: DeriveBuiltin) -> (ModuleId, &'static str, Pa
|
|||
builtins_path.join("Hash.roc"),
|
||||
),
|
||||
DeriveBuiltin::IsEq => (
|
||||
ModuleId::EQ,
|
||||
module_source(ModuleId::EQ),
|
||||
ModuleId::BOOL,
|
||||
module_source(ModuleId::BOOL),
|
||||
builtins_path.join("Eq.roc"),
|
||||
),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1629,7 +1629,7 @@ mod eq {
|
|||
a = @LyingEq 10
|
||||
b = @LyingEq 5
|
||||
c = @LyingEq 5
|
||||
if Eq.isEq a b && !(Eq.isEq b c) then
|
||||
if Bool.isEq a b && !(Bool.isEq b c) then
|
||||
"okay"
|
||||
else
|
||||
"fail"
|
||||
|
|
@ -1647,7 +1647,7 @@ mod eq {
|
|||
r#"
|
||||
app "test" provides [main] to "./platform"
|
||||
|
||||
main = Eq.isEq 10u8 10u8
|
||||
main = Bool.isEq 10u8 10u8
|
||||
"#
|
||||
),
|
||||
true,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue