[Haskell-cafe] RE: ANN: System.FilePath 0.9
u.stenzel at web.de
Wed Jul 26 09:29:01 EDT 2006
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
> > 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
> > 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...
A politician is someone who calls a spade a portable, hand-operated
-- author unknown
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Size: 189 bytes
Desc: Digital signature
Url : http://www.haskell.org//pipermail/haskell-cafe/attachments/20060726/ca06146e/attachment.bin
More information about the Haskell-Cafe