I wasn't happy with the way it dealt with Dir vs File things. In his
version of the library, a `Path b Dir` always ends with a trailing
path separator and `Path b File` never ends with a trailing path separator.
IMO, it is nonsensical to make a Dir vs File distinction on path level,
although it first seems nice.
Some of the reasons are:
* a path is just that: a path. It is completely disconnected from IO level
and even if a `Dir`/`File` type theoretically allows us to say "this path
ought to point to a file", there is literally zero guarantee that it will
hold true at runtime. So this basically gives a false feeling of a
type-safe file distinction.
* it's imprecise about Dir vs File distinction, which makes it even worse,
because a directory is also a file (just not a regular file). Add symlinks
to that and the confusion is complete.
* it makes the API oddly complicated for use cases where we basically don't
care (yet) whether something turns out to be a directory or not
Still, it comes also with a few perks:
* it simplifies some functions, because they now have guarantees whether a
path ends in a trailing path separator or not
* it may be safer for interaction with other library functions, which behave
differently depending on a trailing path separator (like probably shelly)
Not limited to, but also in order to fix my remarks without breaking any
benefits, I did:
* rename the `Dir`/`File` types to `TPS`/`NoTPS`, so it's clear we are only
giving information about trailing path separators and not actual file
types we don't know about yet
* add a `MaybeTPS` type, which does not mess with trailing path separators
and also gives no guarantees about them... then added `toNoTPS` and
`toTPS` to allow type-safe conversion
* make some functions accept more general types, so we don't unnecessarily
force paths with trailing separators for `(</>)` for example... instead
these functions now examine the paths to still have correct behavior.
This is really minor overhead. You might say now "but then I can append
filepath to filepath". Well, as I said... we don't know whether it's a
"filepath" at all.
* merge `filename` and `dirname` into `basename` and make `parent` be
`dirname`, so the function names match the name of the POSIX ones,
which do (almost) the same...
* fix a bug in `basename` (formerly `dirname`) which broke the type
guarantees
* add a pattern synonym for easier pattern matching without exporting
the internal Path constructor
The line was triggering parse error when running haddock:
```
src/Path.hs:16:1:
parse error on input ‘-- | A normalizing well-typed path type.’
```
Removing it works for me.
Here I copied the blog post announcing the library, because it describes
it very well, and not everyone who discovers the library will know where
to look for such a comprehensive description.
http://chrisdone.com/posts/path-package
I've made two edits to that post to reflect new things:
1. On line 123 there is a mention of ‘fromAbsDir’ and other similar
functions.
2. On line 363 I've put a link to my ‘path-io’ package that provides
well-typed interface to ‘directory’ and ‘temporary’. I've written the
package for my personal needs, because I was tired of the endless
conversion and I wanted things like recursive copying of
directories. When I published it, someone opened an issue asking to
add some functions from Stack's ‘Path.IO’ — that's what I'm going to
do. I expect it will be able to replace ‘Path.IO’ in Stack soon. I've
talked to Stack maintainers and they like the package and have
nothing against the switch.
This helps to “double check” programmers' assumptions about what kind of
path he is converting into ‘FilePath’. Without these synonyms it's
possible to silently convert wrong type of path into ‘FilePath’.
The properties for stripDir and parent used the name 'parent' as a
variable.
The properties for filename and dirname seemed to be wrong and also used
'parent' as a variable.