Conversation
| n = number: "It's the number ${toString number}"; | ||
| s = str: "It's the string ${str}"; | ||
| } | ||
| => error: test: No handler for tag "unknown" |
There was a problem hiding this comment.
"test" doesn't seem like a great example. It'd help to have a more realistic use case. When it's a realistic example, it's easier to see what's expected from the context.
When this error occurs in the context of a module that defines an option of type attrTag ..., this case will only occur due to programming error, and I don't think the module author should have the foresight to clarify that in the context.
In other cases, you probably do want the context to be quite general.
Maybe we should have another function that takes an option instead of its value? Doesn't work for attrTags when used as part of type constructors like attrsOf though.
There was a problem hiding this comment.
What if the merged result of attrTag is the matching function itself 🤔
config.some.option {
n = number: "It's the number ${toString number}";
s = str: "It's the string ${str}";
}This would be doable effectively in a backwards-compatible way using __functor! And this way we should be able to get a good error message for free. Not a big fan of __functor in general, but in this case I'm really wondering..
There was a problem hiding this comment.
For my use case, settings, I need to not have it:
… while evaluating attribute '__functor'
error: cannot convert a function to JSON
There was a problem hiding this comment.
I guess it also wouldn't be very backwards compatible, because any code that asserts for the attribute set to only have one attribute would fail.
| ::: | ||
| */ | ||
| matchAttrTag = | ||
| context: value: handlers: |
There was a problem hiding this comment.
| context: value: handlers: | |
| context: handlers: value: |
Often, the handlers are more part of the program than part of the data, so arranging them like this lets us take advantage of currying, in things like map, pipes, or eta-reduced function definitions.
There was a problem hiding this comment.
I think the most common case is to not curry tbh, and you can still use flip if you need it. With the value: handlers: order we're also mirroring how matching looks like in many other languages:
match value {
Foo { .. } => 0
Bar { .. } => 1
}case value of
Foo { .. } -> 0
Bar { .. } -> 1So I'd really prefer leaving it like that
There was a problem hiding this comment.
The annoying thing is that if you do want to lib.flip, you have to write it like flip (matchAttrTag "context") [...] which looks a bit funny to me
There was a problem hiding this comment.
I guess if we go for #304328 (comment) this won't be a problem anymore :D
There was a problem hiding this comment.
Pipe friendly:
map (matchAttrTag "context") myListand
value |> matchAttrTag "context" {
...
}Not pipe friendly:
map (flip (matchAttrTag "context")) myListand
matchAttrTag "context" value {
...
}There was a problem hiding this comment.
Also, fwiw, avoiding flip avoids a runtime cost.
|
Oh this looks really nice. I make extensive use of |
Description of changes
As suggested in #284551 (review), this is a useful utility function for working with values from
lib.types.attrTag:This was written in Nix Hour 68
Ping @roberth
Things done
lib.types.attrTagdocs to mention this functionAdd a 👍 reaction to pull requests you find important.