On Fri, 29 Oct 2004, Andrew Pimlott wrote:
> Well, it's messy, but I don't believe it's that hard. Of course, you'll
> never be correct outside the IO monad, but if you enumerate your
> assumptions about what a path means outside of IO, I think you can come
> up with a fairly coherent set of operations.
Okay, lemme try...
-- Given a directory path "dir" and a file/directory path "rel",
-- returns a merged path "full" with the property that
-- (cd dir; do_something_with rel) is equivalent to
-- (do_something_with full). (XXX is a Nothing return ever needed?)
mergePath :: FilePath -> FilePath -> FilePath
-- Given a file/directory path "full", return a path "dir"
-- referring to a directory which contains that file/dir as an
-- entry, and a path "rel" such that "mergePath dir rel" refers
-- to the same file/dir as "full". Returns NeedIO if the answer
-- cannot be determined without IO operations, and NoParent if
-- there cannot be an answer. (XXX hideous return type)
splitPath :: FilePath -> SplitPathResult
data SplitPathResult = NeedIO | NoParent | Split FilePath FilePath
-- Given path referring to a file or directory, returns a
-- canonicalized path, with the intent that two paths referring
-- to the same file/directory will map to the same canonicalized
-- path. Note that it is impossible to guarantee that the
-- implication (same file/dir <=> same canonicalizedPath) holds
-- in either direction: this function can make only a best-effort
-- attempt. If the path does not refer to an existing file or
-- directory, returns Nothing. (XXX not ideal, but what else can
-- you do?)
canonicalizePath :: FilePath -> IO (Maybe FilePath)
-- Does as much as possible to simplify and regularize a path
-- in a meaning-preserving manner, without IO monad operations.
-- This function is idempotent, and is the identity on all
-- FilePaths returned by FilePath library functions.
-- (XXX there's not much this can do -- it's unsafe to convert
-- "a/b/../c" to "a/c", for example, though I think "a/b/./c"
-- to "a/b/c" is safe.)
normalizePath :: FilePath -> FilePath
-- Returns True if this path's meaning is independent of any OS
-- "working directory", False if it isn't. (XXX would probably be
-- better to make FilePath an abstract type and make it always
-- independent of working directories.)
isAbsolutePath :: FilePath -> Bool
-- Returns True if the path always denotes a directory
-- regardless of the current filesystem state. (XXX is this
-- the right thing for eliminating . and .. from directory
-- listings, or is another function needed?)
isSpecialDirectory :: FilePath -> Bool
-- Returns True if the path denotes a root. This implies
-- isSpecialDirectory and isAbsolutePath, and a NoParent return
-- from splitPath.
isRoot :: FilePath -> Bool
-- getRoots returns a list of paths denoting directories which exist
-- and satisfy isRoot. Can't guarantee to return all of them, since
-- they may include e.g. "\\\\foo\\bar" on Win32.
getRoots :: IO [FilePath]
Omitted:
* functions which operate on file names rather than paths
* functions which can be implemented portably in terms of the above
primitives
* isRootedPath -- I can't see a use for this
* various other stuff
-- Ben