-
-
Notifications
You must be signed in to change notification settings - Fork 173
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
Implement importing paths as Location #585
Conversation
Note that there's no |
|
||
parent </> import₀ = import₁ | ||
canonicalize(import₁) = child | ||
ε ⊢ child : < Local : Text | Remote : Text | Environment : Text | Missing > |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure this is really what I'm after. Firstly, I want normalisation to rule out impossible paths, so Missing
is no good. Next, it seems like Local
doesn't produce an absolute path, which is also what I'm interested in (though maybe less so than ruling out missing files).
But can't I recover Missing
myself with ?
? Can't I write
let add-missing : Location -> Location-With-Missing = ...
in (add-missing (./foo.dhall as Location)) ? Location-With-Missing.Missing
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ocharles would you want Dhall to check if a file exists or not? I would like to represent possibly non-existent paths (e.g. for the case in which you're configuring a tool that will create these paths)
Re making the paths absolute: I don't have a strong opinion on it as it's just about attaching the CWD
to the relative paths, I just feel that it would be special casing, and I have the same feeling about failing on the missing
keyword instead of including it as a constructor.
Do you have a use-case for which you cannot handle Missing
and you cannot handle relative paths?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
would you want Dhall to check if a file exists or not?
Yes.
I would like to represent possibly non-existent paths (e.g. for the case in which you're configuring a tool that will create these paths)
Ok, but I think that is covered by using ? missing
as mentioned in my comment above.
I will have to page in exactly how I want to use this feature to see if I can handle Missing
. It's probably stuff in my Dhall interpreter, so that could throw errors accordingly at runtime. I would, naturally, prefer to avoid runtime errors though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would like to represent possibly non-existent paths (e.g. for the case in which you're configuring a tool that will create these paths)
Ok, on further thought I think I see what you're getting at. We'd like to be able to write
{ config-dir = ./config as Location }
Under my proposal, that is an import failure if ./config
doesn't already exist. Using ?
we don't really have the tools to construct a Location
, the best we can do is:
{ config-dir = (< Existing = ./config as Location | New : Text >) ? (< New = "./config" | Existing : Location >) }
which is a bit meh.
However, what if we had syntax for constructing Location
s? Then we could
{ config-dir = Location "./config" }
The lack of an import here clarifies that this Location
might not exist.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, but I think that is covered by using
? missing
as mentioned in my comment above
I don't see how? I want the path information, not a Missing
. The Missing
constructor would only be used to represent the missing
keyword
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yea, I think I made a mistake in that original comment. I replied to myself with hopefully a bit more clarification.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see. But what's wrong in them looking like imports? The semantics are very close - they are parsed like imports and get canonicalized and chained at import-resolution time - and the only thing that would change would be the semantics of ?
, which will never fail on Location
s
EDIT: and right, the other difference which is related to the change of the ?
semantics is that the paths might not exist, which is why you want to differentiate them, I see now
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One suggestion is that as Location
could also return another Bool
field specifying whether or not the file was present. Then, later on, once we have dependent types you could assert that the file was present using something like this:
let path = ./example.dhall as Location
let _ = Assert : path.present ≡ True
…
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So we had a chat with @ocharles yesterday, and I think we'd like different enough features that they'd warrant different syntax (rather than trying to cram everything in the same syntax):
- "Path representation":
- this is just about representing locations in Dhall
- the syntax could be
./some/import as Location
- it would return a union like proposed by @Gabriel439 above
< Local : Text | Remote : Text | Environment : Text | Missing >
- it would only canonicalize and chain
- it would never resolve (as it's only about representing locations), so it would never fail
- this is what this PR implements
- "Absolute paths resolution":
- this is about having a path resolve to its absolute representation
- the syntax could be
./some/path as AbsolutePath
- it would return a
Text
with the absolute path to a file and it would do the full blown canonicalization, chaining and resolution - it would fail if the file doesn't exist, if the file is on a remote location, and in case of
missing
- this is what @ocharles would like to have (please correct any inaccuracies)
Co-Authored-By: Ollie Charles <ollie@ocharles.org.uk>
Another thing we could do is have the type of the result depend on the type of the import For example:
|
|
I can think of two reasons against this:
|
It seems to me the only real difference between the two is the desire to resolve, or not.
Maybe
./blah as Location Raw
./blah as Location Resolved
or
SomeBuiltin/readlink (./blah as Location)
When you don't want it to work on URLs you can achieve that with merge.
I'm fairly hesitant about all versions of this feature, but especially about two totally separate ones.
|
@singpolyma We did have a little chat about what is essentially a "flag" to the import type, but I'm not huge on - especially as you could just have distinctly named import types and achieve the same thing. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We're at the 7 day mark for making a decision, so I'll decide to approve. I feel that if we have additional substantive changes we wish to make to improve this feature they should be made as subsequent proposals.
I think the discussion has strayed a bit from the problem that @f-f was originally trying to solve for spago
, which I understood as: "provide a path that is referentially transparent". I support that goal because providing language support for referentially transparent paths is a security feature: if users try to refer to paths as Text
fields within their configurations then it risks the host program accidentally reading in the wrong file if the Dhall configuration is interpreted from the wrong location.
As @singpolyma noted: there is a separate discussion about whether or not we should resolve the path to verify that it is there, but I think that should be out of scope for this proposal because:
- (A) it's not addressing the original requirement
- (B) it's not a feature that
spago
needs and I haven't seen an open source tool that does need it (yet) - (C) we can always add it later via a new keyword as noted in this thread, so we're not painting ourselves into a corner by not supporting it yet
It's good that we've got some approval on this, but I'm still a bit unsure on this. I'll try and double check this again tomorrow, and see how it reconciles with mine and @f-f's discussion at ZuriHac. |
I'm still pretty uneasy with the semantics of |
I don't have a strong opinion on it, but I feel it should be there for the same reason we have it in the language in the first place: completeness. More specifically:
On the other hand I agree with you that it's a bit weird that |
I finally managed to put together a proof of concept of this in dhall-lang/dhall-haskell#1019 The implementation was simpler than I expected, as all the machinery is already there |
Do I understand correctly that this change means you can concatenate strings together to import expressions? Or, is this something else entirely? |
@joneshf this is something entirely different: you can think of it as "reflection for imports", where at "runtime" you have an import path (or url, etc) available as a So this is effectively just a "smart newtype" for representing locations (paths and URLs) in Dhall |
Gotcha. Thanks for explaining! |
You're welcome 🙂 |
A couple of fixes for tests: - rename the `asLocation` parser test I introduced in #585 to the correct path - bind the variables in the normalization tests introduced in #592 (normalization tests cannot contain unbound variables because it makes sense to normalize an expression only if it typechecks first)
Fix #71
This standardizes native support for reading import locations into Dhall, as specified by @Gabriel439 in #71 (comment)
So e.g. if you do
..then you'd have it read in Dhall as
The main reason why this is useful as a builtin is that we can exploit the canonicalization and chaining that Dhall uses for imports so that relative paths stay correct over relative importing of other Dhall expressions. This sounds like a mouthful, so here's an example (there is also a test about this):
./nested/import.dhall
containsmissing
./nested/importLocation.dhall
contains./import.dhall as Location
here.dhall
contains./nested/importLocation.dhall
(note that this is a normal import)here.dhall
in the current directory will give:I also noted that
missing
will not fail to resolve when importedas Location
, so e.g. the?
operator will not have the usual behaviour (there's a test about this too)Things I'm unsure of in this PR: