
On Sat, 2009-11-14 at 12:42 +0000, Ben Moseley wrote:
A lovely abstract type would be wonderful, but no one has yet released such a library on hackage...
I'm certainly not going to claim it's 'lovely' ... but there is now on hackage a library which offers an abstract type:
http://hackage.haskell.org/package/pathtype
It's very early days, hasn't been used in anger, doesn't support a lot of Windows things yet, but the basics do work.
Great.
I'd be grateful for any comments (and of course patches!)
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 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?
Oh, and....
*System.Path> takeDirectory ("Main.hs"::RelFile) .
:-) 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. 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. The type distinction would enforce it, and you could see explicitly where paths are deliberately completed relative to the current directory (or some other root). On the other hand it doesn't quite align with people's notion of relative paths so people might hate it :-). 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. For example one could distinguish file names (with no directory part), or pure roots with no directory part (eg ".", "/", "C: \", "//server/share/"). Duncan