File Paths in Haskell

Here’s the translation of the Go file paths example to Haskell:

Our program demonstrates how to work with file paths in Haskell using the filepath module. This module provides functions to parse and construct file paths in a way that is portable between operating systems.

import System.FilePath
import Data.List (stripPrefix)

main :: IO ()
main = do
    -- `combine` should be used to construct paths in a
    -- portable way. It takes any number of arguments
    -- and constructs a hierarchical path from them.
    let p = combine "dir1" $ combine "dir2" "filename"
    putStrLn $ "p: " ++ p

    -- You should always use `combine` instead of
    -- concatenating '/' or '\' manually. In addition
    -- to providing portability, `combine` will also
    -- normalize paths by removing superfluous separators
    -- and directory changes.
    putStrLn $ combine "dir1//" "filename"
    putStrLn $ combine "dir1/../dir1" "filename"

    -- `takeDirectory` and `takeFileName` can be used to split a path to the
    -- directory and the file. Alternatively, `splitFileName` will
    -- return both in the same call.
    putStrLn $ "takeDirectory p: " ++ takeDirectory p
    putStrLn $ "takeFileName p: " ++ takeFileName p

    -- We can check whether a path is absolute.
    putStrLn $ show $ isAbsolute "dir/file"
    putStrLn $ show $ isAbsolute "/dir/file"

    let filename = "config.json"

    -- Some file names have extensions following a dot. We
    -- can split the extension out of such names with `takeExtension`.
    let ext = takeExtension filename
    putStrLn ext

    -- To find the file's name with the extension removed,
    -- use `dropExtension`.
    putStrLn $ dropExtension filename

    -- `makeRelative` finds a relative path between a base and a
    -- target. It returns the target unchanged if it cannot
    -- be made relative to base.
    putStrLn $ makeRelative "a/b" "a/b/t/file"
    putStrLn $ makeRelative "a/b" "a/c/t/file"

To run the program, save it as file-paths.hs and use runhaskell:

$ runhaskell file-paths.hs
p: dir1/dir2/filename
dir1/filename
dir1/filename
takeDirectory p: dir1/dir2
takeFileName p: filename
False
True
.json
config
t/file
../c/t/file

In this Haskell version:

  1. We use the System.FilePath module, which provides similar functionality to Go’s filepath package.
  2. combine is used instead of Join to construct file paths.
  3. takeDirectory and takeFileName are used instead of Dir and Base.
  4. isAbsolute checks if a path is absolute.
  5. takeExtension extracts the file extension.
  6. dropExtension removes the extension from a filename.
  7. makeRelative finds a relative path between two paths.

Note that Haskell’s filepath module doesn’t have an exact equivalent to Go’s filepath.Rel. The makeRelative function is similar but behaves slightly differently when the paths can’t be made relative.

Haskell’s approach to file paths is similar to Go’s, providing a portable way to work with paths across different operating systems.