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
signature.asc
Description: Digital signature
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe