{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE StandaloneDeriving #-}
module Data.Path where
import Control.Category
import Data.Text
(Text)
import qualified Data.Text as T
import Prelude hiding
(id, (.))
import Data.List (foldl')
import qualified System.FilePath.Posix as FilePath
data Root
data Dir
data File
data Path a b where
Nil :: Path a a
ConsRoot :: Path a Root -> Path a Dir
ConsDir :: Text -> Path a Dir -> Path a Dir
ConsFile :: Text -> Path a Dir -> Path a File
deriving instance Show (Path a b)
instance Category Path where
id = Nil
p1 . p2 =
case p1 of
Nil -> p2
ConsRoot p1' -> ConsRoot (p1' . p2)
ConsDir str p1' -> ConsDir str (p1' . p2)
ConsFile str p1' -> ConsFile str (p1' . p2)
root :: Path Root Dir
root = ConsRoot Nil
dir :: Text -> Path Dir Dir
dir p = ConsDir p Nil
file :: Text -> Path Dir File
file p = ConsFile p Nil
toPosixPath :: Path a b -> FilePath
toPosixPath = \case
Nil -> mempty
ConsRoot p -> "/" <> toPosixPath p
ConsDir path p -> toPosixPath p FilePath.</> T.unpack path
ConsFile path p -> toPosixPath p FilePath.</> T.unpack path
fromPosixPath :: FilePath -> Path Root Dir
fromPosixPath = foldl' go root . FilePath.splitDirectories
where
go :: Path Root Dir -> FilePath -> Path Root Dir
go _ "/" = root
go p path = dir (T.pack path) . p
(./) :: Path a b -> Path b c -> Path a c
(./) = (>>>)