Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update stdlib for ADTs #1822

Merged
merged 1 commit into from
Feb 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 60 additions & 10 deletions core/stdlib/std.ncl
Original file line number Diff line number Diff line change
Expand Up @@ -1549,16 +1549,16 @@
error
```
"%
= std.contract.from_predicate std.is_enum,
= std.contract.from_predicate is_enum_tag,

TagOrString
| doc m%%"
Accepts both enum tags and strings. Strings are automatically
converted to an enum tag.

`TagOrString` is typically used in conjunction with an enum type, to
accept both actual enum tags and tags represented as strings (e.g. coming from a
JSON serialization).
accept both actual enum tags and tags represented as strings (e.g.
coming from a JSON serialization).

**Warning**: contracts are applied in-order. The pattern described here
requires that `TagOrString` is applied before the corresponding enum
Expand All @@ -1567,7 +1567,7 @@

# Examples

``` nickel
```nickel
let Schema = {
protocol
| std.enum.TagOrString
Expand All @@ -1589,15 +1589,63 @@
```
"%%
= fun label value =>
let label =
std.contract.label.with_message
"expected either a string or an enum tag"
label
in
%typeof% value
|> match {
'String => %enum_from_str% value,
'Enum => value,
_ =>
std.contract.blame_with_message
"expected either a string or an enum tag"
label,
'Enum =>
if is_enum_variant value then
std.contract.blame label
else
value,
_ => std.contract.blame label,
},

is_enum_tag
: Dyn -> Bool
| doc m%"
Checks if a value is an enum tag. Enum variants (applied to an argument)
aren't considered enum tags.

# Examples

```nickel
std.enum.is_enum_tag 'foo
=> true
std.enum.is_enum_tag 'FooBar
=> true
std.enum.is_enum_tag "tag"
=> false
std.enum.is_enum_tag ('Foo "arg")
=> false
```
"%
= fun value => std.is_enum value && !(%enum_is_variant% value),

is_enum_variant
: Dyn -> Bool
| doc m%"
Checks if a value is an enum variant. Bare enum tags (not applied to an
argument) aren't considered enum variants.

# Examples

```nickel
std.enum.is_enum_variant ('Foo "arg")
=> true
std.enum.is_enum_variant ('Http {version = "1.1"})
=> true
std.enum.is_enum_variant 'foo
=> false
std.enum.is_enum_variant [1, 2, 3]
=> false
```
"%
= fun value => %enum_is_variant% value,
},

function = {
Expand Down Expand Up @@ -2360,7 +2408,9 @@
|| type == 'Number
|| type == 'Bool
|| type == 'String
|| type == 'Enum
# note that `type == 'Enum` isn't sufficient, as it includes enum
# variants
|| std.enum.is_enum_tag value
),

NonEmpty
Expand Down
7 changes: 3 additions & 4 deletions doc/manual/merging.md
Original file line number Diff line number Diff line change
Expand Up @@ -621,9 +621,9 @@ error: missing definition for `required_field2`
8 │ & { foo.required_field1 = "here" }
│ ------------------------ in this record
┌─ <stdlib/std.ncl>:3012:18
┌─ <stdlib/std.ncl>:3062:18
3012 │ = fun x y => %deep_seq% x y,
3062 │ = fun x y => %deep_seq% x y,
│ ------------ accessed here
```

Expand All @@ -640,8 +640,7 @@ let Port
(
fun value =>
std.is_number value
&& value
% 1 == 0
&& value % 1 == 0
&& value >= 0
&& value <= 65535
)
Expand Down
Loading