Simon Marlow simonmarhaskell at
Tue Dec 11 09:22:14 EST 2007

Ian Lynagh wrote:
> On Sun, Dec 09, 2007 at 09:17:56PM +0000, Neil Mitchell wrote:
>>> The first is this:
>>>     Prelude System.FilePath> "." </> "foo"
>>>     "./foo"
>>> which means we get things like
>>>     [2 of 2] Compiling GHC.Foo          ( ./GHC/Foo.hs, ./GHC/Foo.o )
>>> rather than
>>>     [2 of 2] Compiling GHC.Foo          ( GHC/Foo.hs, GHC/Foo.o )
>>> Is there a reason the result shouldn't be "foo"?
>> My best guess is that "." </> "foo" should equal "./foo". However, I'm
>> not overly wedded to this behaviour, so if the general consensus is
>> the other way, I'll happily implement that.
>>> Possibly relatedly, the current directory seems to be "" rather than
>>> ".". This turns up in at least a couple of areas:
>>>     Prelude System.FilePath> normalise "."
>>>     ""
>> I would say this is a bug, and that normalise "." should be ".".
> The two answers above together mean that the property
>     \x y -> let x' = normalise x
>                 y' = normalise y
>                 z = x' </> y'
>             in z == normalise z'
> doesn't hold (for x = ".", y = "foo"), but it is one I would expect to
> hold.

I think you have an extra ' on the last line of the code above.  But 
anyway, why do you expect that to hold?

There's an implicit context in the definition of normalise.  The invariant 
we want is that I can use "normalise x" wherever I use "x" and get the same 
result.  But it can't be that simple, because we can always tell the 
difference by looking at the string, so we have to define the allowable 
context carefully.  It looks like the context we're aiming for is "all 
functions in System.FilePath, System.IO and System.Directory".

Which would make "./foo" the same as "foo": as far as the OS is concerned, 
these always mean the same thing.

execvp mucks things up by giving a special meaning to "foo".  But all this 
means is that execvp (and hence rawSystem) is a context that can tell the 
difference between "normalise x" and "x", and therefore you shouldn't call 
normalise on the path given to rawSystem.

>>>     Prelude System.FilePath> splitFileName "foo"
>>>     ("","foo")
>> I'd say this was expected. In a similar way, takeDirectory "foo" gives
>> "", not "./".
> I'd expect takeDirectory "foo" to be "." and dropFileName "foo" to be
> "./" too.

Right, me too.

But this is more of a pervasive design choice.  It looks like 
System.FilePath consistently treats "" as a valid FilePath meaning "the 
current directory", and this would mean changing that policy.

As far as System.Directory is concerned, "" is not a valid FilePath (i.e. 
you can't say getDirectoryContents ""), and the current directory is 
denoted by ".".  So it would seem sensible for System.FilePath to behave in 
the same way.

But then (splitFileName "foo") would have to give (".", "foo"), and therefore

   uncurry (</>) (splitFileName x)  /=  x

which seems odd.  But perhaps the right property is

   normalise (uncurry (</>) (splitFileName x))  ==  normalise x


More information about the Libraries mailing list