
Andrew Pimlott wrote:
The drive functions stand on their own as a chunk, and are possibly not well suited to a Posix system, but are critical for a Windows system.
Why are they critical for portable code? I am fine with Windows-specific functions, but I think it's a mistake to bundle them [with] portable functions.
I couldn't agree more. In fact, why can't we pretend the world is sane at least within Haskell and just put away those drive letters?
My criticism is that your properties are all specified in terms of string manipulation.
Exactly. I believe, a FilePath should be an algebraic datatype. Most operations on that don't have to be specified, because they are simple and have an obvious effect. Add a system specific parser and a system specific renderer, maybe also define a canonical format, and the headaches stop. What's wrong with this? data FilePath = Absolute RelFilePath | Relative RelFilePath data RelFilePath = ThisDirectory | File String | ParentOf RelFilePath | String :|: RelFilePath parseSystemPath :: String -> Maybe FilePath renderSystemPath :: FilePath -> String We can even clearly distiguish between the name of a directory in its parent and the directory itself. On Windows, the root directory just contains the drive letters and is read-only, drive-absolute-but-directory-relative paths are simply ignored (they are a dumb idea anyway). Seperator characters are never exposed, all we need now is a mapping from Unicode to whatever the system wants.
pathSeparator :: Char The character that seperates directories.
So what do I do with this? If I need it, it seems like the module has failed.
Indeed.
splitFileName "bob" == ("", "bob")
"" is not a directory.
Some problems just vanish: parseSystemPath "bob" == Just (Relative (File "bob")) splitFileName (Relative (File "bob")) = (Relative ThisDirectory, File "bob")
Windows: splitFileName "c:" == ("c:","")
"c:" is arguably not a directory.
parseSystemPath "c:" == Nothing parseSystemPath "c:\" == Absolute ("C:" :|: ThisDirectory)
(Consider that "dir c:" lists the current directory on c:, not c:\)
I'd rather ignore that altogether. Multiple roots with associated "current directories" are just a needless headache. Even a "current directory" is somewhat ill-fitted for a functional language like Haskell.
getFileName "test/" == ""
"" is not a filename.
getFileName (Relative ("test" :|: ThisDirectory)) == error "pattern match failure"
Also, it looks from this that you treat paths differently depending on whether they end in a separator. Yet this makes no difference to the system. That seems wrong to me.
Not to the system, but some programs like to make a difference. If you give rsync a path that doesn't end in a slash, it will take that to mean the directory. With a slash, it means the contents of the directory. The difference is an additional path component that ends up on the target file system or doesn't.
getDirectory :: FilePath -> FilePath Get the directory name, move up one level.
What does this mean, in the presence of dots and symlinks?
You're right, this has to be ill-defined. Instead it should be moveUp :: FilePath -> IO FilePath which would end up in the parent of the linked-to directory after following a symlink. Cutting of a component is done by simple pattern matching, no special functions needed. Sorry for the rant, but this is Haskell, not Perl. We have true data types, not just strings... Udo. -- A politician is someone who calls a spade a portable, hand-operated digging implement. -- author unknown