Draft
Conversation
If we optionally allow providing a function as a matcher on a
single-constructor type, then it follows that we would allow a value for
matching on a unary type as well:
```
> unit = adt.struct "unit" adt.fields.none
> unit.match unit.ctors.make 5
5
```
However, this would make using the long-form attrset for matching on the
same type ambiguous:
```
> unit = adt.struct "unit" adt.fields.none
> unit.match unit.ctors.make { make = 5; }
\# should this be `5` or `{ make = 5; }`?
```
To prevent this, this switches back to requiring attrsets to avoid
ambiguity.
Owner
|
i had a thought that maybe an adt framework should be implemented outside of nix-std. i'm not sure though. either that or we can implement it here, and make sure it's known to be very experimental. |
|
what it is ? https://en.wikipedia.org/wiki/Abstract_data_type ? sounds fits LISP (NIX). like define type system and rules and generate types adhering these. |
Collaborator
Author
|
No; algebraic data types, a la structs and Rust-style enums |
|
for Nix to handle K8S YAMLs it kind of should be somewhat there (enum), they often has several types for same YAML node value. none of K8S nix integration do that (yet), neither modules do that too https://github.com/NixOS/nixpkgs/blob/master/lib/options.nix |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Tracking PR for WIP implementation of automatic ADT generation.
Currently, the API is as follows:
Call
adt.newwith a set of constructor names to constructor specifications to automatically generate an ADT. The returned set includes a match function, a check function, and an attrset of the constructorsadt.structis shorthand for ADTs with only one constructor, and names the constructormake.Every constructor has a specification for its fields, which can be typed or untyped. Available specifications are in
adt.fields.positional [ { name = "x"; type = types.int; } { name = "y"; type = types.int; } ]would make a constructor likemake 1 2, and a match function like{ make = x: y: ...; }positional_ [ "x" "y" ]is the same, but untypedrecord { x = types.int; y = types.int }would make a constructor likemake { x = 1; y = 2; }, and a match function like{ make = { x, y }: ...; }record_ ["x" "y"]is the same, but untypednoneis for unary constructors, likeadt.struct "unit" adt.fields.noneanon [ types.int types.int ]is likepositional, but the internal field names are automatically generatedanon_ 2is likepositional_, but the internal field names are automatically generatedCurrently, the only typechecking is via
check. Constructors do not typecheck their arguments, since this would be awful for slow-to-check types.checkwill check both the field types andadt's autogenerated annotationsmatchis used the same aslist.match, etc. Whilematchcould hypothetically be a key in the value, I kept it separate for consistency with these functions.Some questions to answer:
check?adt.structname the single constructormake,new, etc., or name it after the type name? For example,unit = adt.struct "unit" adt.fields.nonewould currently haveunit.ctors.make, which doesn't make too much sense, but the user can always unpack the result and rename everything.adt.structused to allow optionally using a plain function (e.g.point.match p (x: y: x + y)) instead of the full single-element attrset (e.g.point.match p { make = x: y: x + y; }) but this was found to be ambiguous on types with one value, where you naturally could just use a value here. For example, shouldunit.match x { make = 5; }return5or{ make = 5; }? As a solution, I temporarily removed the shorthand. One possible solution is to arbitrarily require a one-argument function for such a type that we arbitrarily passnullto, but this is pretty inconsistent and not that great either.ctorsfield and we just have the user unpack everything into the API they want to expose?__toString? Could we support user-generated__toStrings?adt.new "ordering" { gt = adt.fields.none; eq = adt.fields.none; lt = adt.fields.none; }. Where would we put these?Also could use tests and much better docs.