mirror of
https://github.com/roc-lang/roc.git
synced 2025-07-19 12:35:07 +00:00
Add Eq
to the standard library
This commit is contained in:
parent
b2e7fd91ab
commit
16d12a51c2
7 changed files with 73 additions and 3 deletions
39
crates/compiler/builtins/roc/Eq.roc
Normal file
39
crates/compiler/builtins/roc/Eq.roc
Normal file
|
@ -0,0 +1,39 @@
|
|||
interface Eq
|
||||
exposes [
|
||||
Eq,
|
||||
isEq,
|
||||
isNotEq,
|
||||
]
|
||||
imports [
|
||||
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)
|
|
@ -1291,7 +1291,7 @@ toF64Checked : Num * -> Result F64 [OutOfBounds]*
|
|||
## >>> Num.isNaN (Num.pow -1 0.5)
|
||||
##
|
||||
## *NaN* is unusual from other numberic values in that:
|
||||
## * *NaN* is not equal to any other number, even itself. [Bool.isEq] always returns `Bool.false` if either argument is *NaN*.
|
||||
## * *NaN* is not equal to any other number, even itself. [Eq.isEq] always returns `Bool.false` if either argument is *NaN*.
|
||||
## * *NaN* has no ordering, so [isLt], [isLte], [isGt], and [isGte] always return `Bool.false` if either argument is *NaN*.
|
||||
##
|
||||
## These rules come from the [IEEE-754](https://en.wikipedia.org/wiki/IEEE_754)
|
||||
|
|
|
@ -14,6 +14,7 @@ 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",
|
||||
|
@ -33,4 +34,5 @@ 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");
|
||||
|
|
|
@ -178,6 +178,7 @@ impl Default for ModuleCache<'_> {
|
|||
ENCODE,
|
||||
DECODE,
|
||||
HASH,
|
||||
EQ,
|
||||
JSON,
|
||||
}
|
||||
|
||||
|
@ -2244,6 +2245,7 @@ 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
|
||||
|
@ -3278,6 +3280,7 @@ fn load_module<'a>(
|
|||
"Encode", ModuleId::ENCODE
|
||||
"Decode", ModuleId::DECODE
|
||||
"Hash", ModuleId::HASH
|
||||
"Eq", ModuleId::EQ
|
||||
"Json", ModuleId::JSON
|
||||
}
|
||||
|
||||
|
@ -4768,6 +4771,7 @@ fn canonicalize_and_constrain<'a>(
|
|||
| ModuleId::DICT
|
||||
| ModuleId::SET
|
||||
| ModuleId::HASH
|
||||
| ModuleId::EQ
|
||||
);
|
||||
|
||||
if !name.is_builtin() || should_include_builtin {
|
||||
|
|
|
@ -86,6 +86,7 @@ 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 {
|
||||
|
|
|
@ -1513,9 +1513,15 @@ define_builtins! {
|
|||
15 HASH_HASH_STR_BYTES: "hashStrBytes"
|
||||
16 HASH_HASH_LIST: "hashList"
|
||||
}
|
||||
14 JSON: "Json" => {
|
||||
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" => {
|
||||
0 JSON_JSON: "Json"
|
||||
}
|
||||
|
||||
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)
|
||||
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)
|
||||
}
|
||||
|
|
|
@ -7972,4 +7972,22 @@ mod solve_expr {
|
|||
"O",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn custom_implement_eq() {
|
||||
infer_eq_without_problem(
|
||||
indoc!(
|
||||
r#"
|
||||
app "test" provides [main] to "./platform"
|
||||
|
||||
Trivial := {} has [Eq {isEq}]
|
||||
|
||||
isEq = \@Trivial {}, @Trivial {} -> Bool.true
|
||||
|
||||
main = Eq.isEq (@Trivial {}) (@Trivial {})
|
||||
"#
|
||||
),
|
||||
"Bool",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue