Closed zefir01 closed 2 months ago
Hello,
The issue you're seeing is that the typechecker is expecting a function for getConditions
, but it can only deduce that it has type Dyn
.
When using a type annotation ready : Bool
, the static typechecker kicks in - as in any general purpose programming language out there. The static typechecker is strict by nature, and beside a few exceptions, anything that isn't typed is considered Dyn
- thus, because getConditions
and getResources
aren't annotated, they aren't typechecked, and the typechecker doesn't know their types.
In other words, static typing is "contagious": if you function f
from within a statically typed function g
, then f
usually needs to be typed as well.
Usually, my general advice in this case would thus be to add the missing type annotation on getResources
and getConditions
.
However, in your case, it's not gonna be very easy, because cmd
is dynamically imported, and you're dynamically looking for some fields in it, and using a contract Resource
in the mix, which isn't very easy to handle with static typing.
The simplest one, although the less "safe" (the one with less safety checks), is to turn your type annotation into a contract annotation. Instead of being checked statically by the typechecker, it will be checked at runtime (that the input is a String
and the return value is a Resource
), and the typechecker doesn't verify the content of the function anymore.
Another solution is to keep _resource
typed, and push the contract annotations to getConditions
and getResources
. This requires to come up with slightly more elaborate types. The benefit is that more stuff is checked; in particular _resource
is still statically typechecked.
Here is a working example of 2.:
let cmd = import "command.yaml" in
let Resource = {
_crossform = {
id | String,
ttt | String = "ggg",
},
..
}
in
let getResource
| String -> Array { .. }
= fun _id =>
if std.record.has_field _id cmd.observed then
cmd.observed."%{_id}".resource.unstructured.object
else
{}
in
let getConditions | String -> Array {type: String, status: String; Dyn} = fun _id =>
getResource _id |> match {
{ status={conditions, ..}, .. } => conditions,
_ => []
}
in
let _resource : String -> Resource = fun _id =>
{
_crossform = {
id : String = _id,
ready : Bool =
std.array.any
(
fun x =>
x.type == "Ready"
&& x.status == "True"
)
(getConditions _id)
&& std.array.any
(
fun x =>
x.type == "Synced" && x.status == "True"
)
(getConditions _id),
#test=getConditions _id
}
}
& getResource _id | Resource
in
{
resource = _resource,
}
The type {type: String, status: String; Dyn}
represents record that have at least fields type
and status
, but might have more fields as well. I don't know what your actual data look like; if in command.yaml
there are never other fields than type
and status
, you can get rid of the ; Dyn
part.
Note that, beside reformatting, I also had to fix some errors: you missed parentheses around getConditions _id
in the calls to any
. As you wrote it, it's like you're passing 3 arguments to any
: the function, another function getConditions
, and at last a String _id
. This was caught by typechecker after annotating getResources
and getConditions
, which is a good illustration why approach 2 is safer!
Additionally, It's not an error, but I've simplified your two match statements to only one: you can actually nest patterns in a match
.
In general, I would advise to add more parentheses when things aren't obvious: for example, I find that the line
& getResource _id | Resource
might make it look like the Resource
contract is applied only to getResource _id
, while actually it's applied to the whole merge expression. I would add parentheses to make this clear (but this is only a matter of taste here, not correctness, as |
has lower precedence than most operators).
Also, feel free to improve the annotation of getResources
or getConditions
if you know more precise types for them!
thank you very much. this solves the problem.
Hello. When importing yaml I see a strange error in std.array.any is this a bug or a feature? what am I doing wrong?
To Reproduce crossform.ncl:
main.ncl:
command.yaml:
output:
Environment
Distributor ID: Ubuntu Description: Ubuntu 22.04.4 LTS Release: 22.04 Codename: jammy
Version of the code: nickel-lang-cli nickel 1.5.0 (rev Homebre).