Skip to content

feat(core): add fixedTo.{atLeast,exactly,upTo}#340

Merged
vic merged 13 commits intodenful:mainfrom
DylanRJohnston:dylan.johnston/fixedTo
Apr 7, 2026
Merged

feat(core): add fixedTo.{atLeast,exactly,upTo}#340
vic merged 13 commits intodenful:mainfrom
DylanRJohnston:dylan.johnston/fixedTo

Conversation

@DylanRJohnston
Copy link
Copy Markdown
Collaborator

Overview

Adds new features, early draft, wanted to get your opinion on the design before committing to cleaning it up and potentially breaking it into smaller focused PRs. Needs documentation update too.

den.lib.take.upTo

Uses the same predicate as atLeast to decide whether to invoke a function, but calls the function with only the arguments it supports unlike atLeast which will call the function with extra arguments causing an error unless the function signature uses .... In my opinion this is how atLeast should function, but I understand that this is a breaking change if anyone is using args@{ ctxKey, ... } to capture the full context. So I've introduced this as a seperate parametric type.

den.lib.canTake.upTo

An alias of den.lib.canTake.atLeast provided for API symmetry between den.lib.canTake and den.lib.take

den.lib.recursiveFunctor

Much like den.lib.functor this takes an apply function and an aspect and applies it to each include in the aspects includes list. However, this also recurses into the include list and applies the function down the include tree. Much like fixedTo does but without owned or static aspects.

Caveat: This currently doesn't resolve static or parametric includes and then recurse into their includes if they exist, should it? I'm not sure why you would write aspects with this configuration, but it's theoretically possible. I originally didn't implement this because I thought it would be too complicated, but I think you can just call the aspects with ctx and static ctx and then recurse into them to get at them?

den.lib.parametric.fixedTo.{exactly,atLeast,upTo}

This family of fixedTo variants, follow fixedTo's ability to recurse into the import tree, but do not evaluate owned or static aspects. This reflects the relationship between parametric.__functor and parametric.{exactly,atLeast,upTo}.

Comment thread templates/ci/modules/features/parametric.nix Outdated
Comment thread templates/ci/modules/features/parametric.nix Outdated
@vic
Copy link
Copy Markdown
Member

vic commented Mar 27, 2026

Hey @DylanRJohnston you are awesome, I like this very much!

Indeed, adding all these parametrics makes sense, thanks for taking the time to make this PR.

Some notes:

  • Today I merged improve(core): Remove flake-aspects dependency and code cleanup. #335 and it was big, so this branch has conflicts. I recommend splitting this PR. You will notice I tried to start some parametric.deep <functor> combinator but actually never finished it, feel free to refactor/remove it because your recursiveFunctor is better. As long as our current tests are green you are free to move our impl.

  • We don't use |> pipe operator, since that needs people to enable an experimental feature and we can't rely on non-standard features. use lib.pipe.

  • Yes, please split tests, use sub-directories if you like, naming is important flake.tests.<suite> so we can run just ci <suite>, other than that, feel free to split large tests into their own modules.

  • It is ok if tests use custom ctx, denTest are isolated and it is actually good we can use them for testing how parametric families behave.

I won't have internet today and maybe also not tomorrow. (My dad is having a surgery today and I'll be at the hospital, and tomorrow I get baptized at church -- so maybe I can get back to you on this until sunday).

Thanks for all your effort on this :)

Btw, if you can experiment and switch our default functor to be upTo and tests pass feel free. :)

@vic vic added the allow-ci allow all CI integration tests label Mar 27, 2026
Comment thread templates/ci/modules/features/parametric.nix Outdated
Comment thread templates/ci/modules/features/parametric.nix Outdated
Comment thread templates/ci/modules/features/parametric.nix Outdated
Comment thread templates/ci/modules/features/parametric.nix Outdated
vic added a commit that referenced this pull request Apr 6, 2026
@vic
Copy link
Copy Markdown
Member

vic commented Apr 6, 2026

Hey @DylanRJohnston, I'm trying to make some progress on this, starting with merging upTo at #384

vic added a commit that referenced this pull request Apr 6, 2026
Comment thread nix/lib/can-take.nix
satisfied = valid && builtins.all (n: params ? ${n}) required;
exactly = valid && required == builtins.attrNames params;
upTo = valid && intersect != { };
upTo = satisfied && intersect != { };
Copy link
Copy Markdown
Collaborator Author

@DylanRJohnston DylanRJohnston Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

upTo shouldn't return true for functions that require more than you're able to provide, the previous implementation returned true for canTake { host = true } ({ host, user }: {})

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, I have some usage of upTo in den core, lets see if tests pass.

Comment thread nix/lib/parametric.nix
Comment on lines -15 to 22
deepRecurse =
functor: ctx: provided:
provided
mapIncludes =
branch: leaf: aspect:
aspect
// {
includes = map (
include:
if include ? includes then
if include ? __functor then include else parametric.deep functor ctx include
else
include
) (provided.includes or [ ]);
include: if include ? includes && !include ? __functor then branch include else leaf include
) (aspect.includes or [ ]);
};
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The name change comes from the fact that this function isn't recursive anymore, it just applies two different functions to one level of the include tree, one for branches, and one for leaves.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

Comment thread nix/lib/parametric.nix Outdated
Comment on lines +55 to +61
parametric.deepOwned = functor: deepRecurse includeOwnedAndStatics functor lib.id;
parametric.deepParametrics = functor: deepRecurse includeNothing lib.id functor;

parametric.fixedTo.__functor = _: attrs: parametric.deepOwned (lib.flip parametric.atLeast attrs);
parametric.fixedTo.exactly = attrs: parametric.deepParametrics (lib.flip take.exactly attrs);
parametric.fixedTo.atLeast = attrs: parametric.deepParametrics (lib.flip take.atLeast attrs);
parametric.fixedTo.upTo = attrs: parametric.deepParametrics (lib.flip take.upTo attrs);
Copy link
Copy Markdown
Collaborator Author

@DylanRJohnston DylanRJohnston Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When implementations unify it's usually a good sign you're on the right track. I found I was able to unify the recursion in my implementation with the recursion in parametric.deep. Interestingly one applies the functor on the node in the include tree before it gets traversed, the other applies the functor at the leaf nodes. Not 100% sure why the difference is required or if one could be massaged into the other.

I found it particularly interesting that attrs / ctx could be factored out right to the top level and is no longer interleaved through the include tree traversal but instead is only partially applied to the functor.

@DylanRJohnston DylanRJohnston marked this pull request as ready for review April 7, 2026 09:19
@DylanRJohnston DylanRJohnston changed the title [WIP]: feat: add fixedTo.{atLeast,exactly,upTo} feat(core): add fixedTo.{atLeast,exactly,upTo} Apr 7, 2026
@DylanRJohnston DylanRJohnston requested a review from vic April 7, 2026 09:19
Comment thread nix/lib/can-take.nix Outdated
Comment thread templates/ci/modules/features/parametric-fixedTo.nix Outdated
@vic
Copy link
Copy Markdown
Member

vic commented Apr 7, 2026

Awesome @DylanRJohnston everything is green, shall we merge ?

@DylanRJohnston
Copy link
Copy Markdown
Collaborator Author

Awesome @DylanRJohnston everything is green, shall we merge ?
Yeah so long as you're happy with the names of everything

@vic
Copy link
Copy Markdown
Member

vic commented Apr 7, 2026

I like much more the names you use than mine :D. I will merge, infinite thanks!

Hopefully later we can make your wish come true, make upTo the default parametric.

@vic vic merged commit 6f4179c into denful:main Apr 7, 2026
15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

allow-ci allow all CI integration tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants