
On 14 Nov 2009, at 14:02, Duncan Coutts wrote:
So the type distinctions you are making are:
* whether a path refers to a file or to a directory * whether a path is relative or absolute
Yep, that's the idea.
By relative and absolute it looks like you mean whether it starts with the root "/" vs not. So "foo/bar.txt" and "./foo/bar.txt" are both considered as relative.
Yes.
So in the similar design I was working on, instead of distinguishing relative and absolute, I distinguish incomplete and complete. I initially started with the relative/absolute distinction and moved onto this one. It'd be interesting to see which is most useful in practise.
What I mean by complete is a path referring to an actual file/dir that you could pass to a system call. This means they are anchored to some point the system knows about, such a "." the current directory or "/" or "C:\".
Then an incomplete path is one that is not anchored. Incomplete paths become complete by > them to a existing complete one (including the current dir).
So the difference between this complete/incomplete notion and relative/absolute is for paths that are relative to the current directory.
You would say "Main.hs" :: RelFile
and
readFile :: AbsRelClass ar => FilePath ar -> IO String
and so readFile "Main.hs" is ok, and reads the file "./Main.hs" in the current directory.
I would probably say, "Main.hs" :: IncompleteFilePath
(though I think I used somewhat shorter type names than that!)
and
readFile :: CompleteFilePath -> IO String
and thus readFile "Main.hs" is not well typed, instead it would be:
readFile (currentDir > "Main.hs")
because that gives us a complete path, and if we want that to be rooted at the processes' current directory, then we do so explicitly.
Ah, ok, I see. I can see the attraction to that.
My intuition with file paths in Cabal, is that this distinction would catch more bugs. Ideally cabal's building code would be independent of the current directory, but the fact that relative paths get automagically completed to being relative to the current directory means that it's very easy to break this property.
Interesting. One possible approach with pathtype as it stands would be a wrapper module which hides "readFile :: AbsRelClass ar => FilePath ar -> IO String" and exposes it only at the restricted type: "readAbsFile :: AbsFile -> IO String; readAbsFile = readFile". This blocks accidental reading of relative files and clients are forced to use something like 'makeAbsoluteFromCwd'. I don't think this is exactly the same as what you're suggesting (it doesn't permit the "completion" process to be separated from the reading), but I think it would be a way to catch some of the same bugs?
There are various other distinctions one could try to make, the question becomes which type distinctions are useful and when does it just become too much.
I think this is a very important point. It's definitely a balancing act. I have ondered whether even capturing Abs/Rel was overkill, but my current feeling (not yet based on much real-world experience) is that it is worth it. Cheers, --Ben