Safe Haskell | Safe-Inferred |
---|---|
Language | Haskell2010 |
Synopsis
- (<|>) :: Alternative f => f a -> f a -> f a
- bracket :: IO a -> (a -> IO b) -> (a -> IO c) -> IO c
- join :: Monad m => m (m a) -> m a
- void :: Functor f => f a -> f ()
- (>=>) :: Monad m => (a -> m b) -> (b -> m c) -> a -> m c
- (<=<) :: Monad m => (b -> m c) -> (a -> m b) -> a -> m c
- forM :: (Traversable t, Monad m) => t a -> (a -> m b) -> m (t b)
- class Monad m => MonadError e (m :: Type -> Type) | m -> e where
- throwError :: e -> m a
- catchError :: m a -> (e -> m a) -> m a
- lift :: (MonadTrans t, Monad m) => m a -> t m a
- second :: Bifunctor p => (b -> c) -> p a b -> p a c
- bimap :: Bifunctor p => (a -> b) -> (c -> d) -> p a c -> p b d
- first :: Bifunctor p => (a -> b) -> p a c -> p b c
- bool :: a -> a -> Bool -> a
- sequenceA_ :: (Foldable t, Applicative f) => t (f a) -> f ()
- (<&>) :: Functor f => f a -> (a -> b) -> f b
- intercalate :: [a] -> [[a]] -> [a]
- isSuffixOf :: Eq a => [a] -> [a] -> Bool
- isPrefixOf :: Eq a => [a] -> [a] -> Bool
- fromJust :: HasCallStack => Maybe a -> a
- fromMaybe :: a -> Maybe a -> a
- maybeToList :: Maybe a -> [a]
- maybe :: b -> (a -> b) -> Maybe a -> b
- isNothing :: Maybe a -> Bool
- isJust :: Maybe a -> Bool
- data ZonedTime
- formatTime :: FormatTime t => TimeLocale -> String -> t -> String
- parseTimeM :: (MonadFail m, ParseTime t) => Bool -> TimeLocale -> String -> String -> m t
- data TimeLocale
- data FeedConfiguration = FeedConfiguration {}
- data Redirect = Redirect {
- redirectTo :: String
- relativizeUrls :: Item String -> Compiler (Item String)
- escapeHtml :: String -> String
- toUrl :: FilePath -> String
- copyFileCompiler :: Compiler (Item CopyFile)
- rulesExtraDependencies :: [Dependency] -> Rules a -> Rules a
- route :: Routes -> Rules ()
- compile :: (Binary a, Typeable a, Writable a) => Compiler (Item a) -> Rules ()
- version :: String -> Rules () -> Rules ()
- create :: [Identifier] -> Rules () -> Rules ()
- match :: Pattern -> Rules () -> Rules ()
- data Rules a
- class Writable a where
- debugCompiler :: String -> Compiler ()
- withErrorMessage :: String -> Compiler a -> Compiler a
- noResult :: String -> Compiler a
- unsafeCompiler :: IO a -> Compiler a
- cached :: (Binary a, Typeable a) => String -> Compiler a -> Compiler a
- saveSnapshot :: (Binary a, Typeable a) => Snapshot -> Item a -> Compiler (Item a)
- getResourceString :: Compiler (Item String)
- getResourceBody :: Compiler (Item String)
- getRoute :: Identifier -> Compiler (Maybe FilePath)
- makeItem :: a -> Compiler (Item a)
- loadSnapshotBody :: (Binary a, Typeable a) => Identifier -> Snapshot -> Compiler a
- loadBody :: (Binary a, Typeable a) => Identifier -> Compiler a
- loadSnapshot :: (Binary a, Typeable a) => Identifier -> Snapshot -> Compiler (Item a)
- load :: (Binary a, Typeable a) => Identifier -> Compiler (Item a)
- withItemBody :: (a -> Compiler b) -> Item a -> Compiler (Item b)
- itemSetBody :: a -> Item b -> Item a
- data Item a = Item {
- itemIdentifier :: Identifier
- itemBody :: a
- type Snapshot = String
- data Compiler a
- composeRoutes :: Routes -> Routes -> Routes
- metadataRoute :: (Metadata -> Routes) -> Routes
- gsubRoute :: String -> (String -> String) -> Routes
- constRoute :: FilePath -> Routes
- customRoute :: (Identifier -> FilePath) -> Routes
- matchRoute :: Pattern -> Routes -> Routes
- setExtension :: String -> Routes
- idRoute :: Routes
- data Routes
- makePatternDependency :: MonadMetadata m => Pattern -> m Dependency
- lookupString :: String -> Metadata -> Maybe String
- type Metadata = Object
- getMatches :: MonadMetadata m => Pattern -> m [Identifier]
- getMetadata :: MonadMetadata m => Identifier -> m Metadata
- data Dependency
- (.||.) :: Pattern -> Pattern -> Pattern
- (.&&.) :: Pattern -> Pattern -> Pattern
- hasNoVersion :: Pattern
- hasVersion :: String -> Pattern
- fromRegex :: String -> Pattern
- fromList :: [Identifier] -> Pattern
- data Pattern
- toFilePath :: Identifier -> FilePath
- fromFilePath :: FilePath -> Identifier
- data Identifier
- doesFileExist :: FilePath -> IO Bool
- copyFile :: FilePath -> FilePath -> IO ()
- createDirectoryIfMissing :: Bool -> FilePath -> IO ()
- splitDirectories :: FilePath -> [FilePath]
- (</>) :: FilePath -> FilePath -> FilePath
- takeDirectory :: FilePath -> FilePath
- takeFileName :: FilePath -> FilePath
- splitFileName :: FilePath -> (String, String)
- dropExtension :: FilePath -> FilePath
Documentation
(<|>) :: Alternative f => f a -> f a -> f a infixl 3 #
An associative binary operation
:: IO a | computation to run first ("acquire resource") |
-> (a -> IO b) | computation to run last ("release resource") |
-> (a -> IO c) | computation to run in-between |
-> IO c |
When you want to acquire a resource, do some work with it, and
then release the resource, it is a good idea to use bracket
,
because bracket
will install the necessary exception handler to
release the resource in the event that an exception is raised
during the computation. If an exception is raised, then bracket
will
re-raise the exception (after performing the release).
A common example is opening a file:
bracket (openFile "filename" ReadMode) (hClose) (\fileHandle -> do { ... })
The arguments to bracket
are in this order so that we can partially apply
it, e.g.:
withFile name mode = bracket (openFile name mode) hClose
Bracket wraps the release action with mask
, which is sufficient to ensure
that the release action executes to completion when it does not invoke any
interruptible actions, even in the presence of asynchronous exceptions. For
example, hClose
is uninterruptible when it is not racing other uses of the
handle. Similarly, closing a socket (from "network" package) is also
uninterruptible under similar conditions. An example of an interruptible
action is killThread
. Completion of interruptible release actions can be
ensured by wrapping them in in uninterruptibleMask_
, but this risks making
the program non-responsive to Control-C
, or timeouts. Another option is to
run the release action asynchronously in its own thread:
void $ uninterruptibleMask_ $ forkIO $ do { ... }
The resource will be released as soon as possible, but the thread that invoked bracket will not block in an uninterruptible state.
join :: Monad m => m (m a) -> m a #
The join
function is the conventional monad join operator. It
is used to remove one level of monadic structure, projecting its
bound argument into the outer level.
'
' can be understood as the join
bssdo
expression
do bs <- bss bs
Examples
A common use of join
is to run an IO
computation returned from
an STM
transaction, since STM
transactions
can't perform IO
directly. Recall that
atomically
:: STM a -> IO a
is used to run STM
transactions atomically. So, by
specializing the types of atomically
and join
to
atomically
:: STM (IO b) -> IO (IO b)join
:: IO (IO b) -> IO b
we can compose them as
join
.atomically
:: STM (IO b) -> IO b
void :: Functor f => f a -> f () #
discards or ignores the result of evaluation, such
as the return value of an void
valueIO
action.
Examples
Replace the contents of a
with unit:Maybe
Int
>>>
void Nothing
Nothing>>>
void (Just 3)
Just ()
Replace the contents of an
with unit, resulting in an Either
Int
Int
:Either
Int
()
>>>
void (Left 8675309)
Left 8675309>>>
void (Right 8675309)
Right ()
Replace every element of a list with unit:
>>>
void [1,2,3]
[(),(),()]
Replace the second element of a pair with unit:
>>>
void (1,2)
(1,())
Discard the result of an IO
action:
>>>
mapM print [1,2]
1 2 [(),()]>>>
void $ mapM print [1,2]
1 2
(>=>) :: Monad m => (a -> m b) -> (b -> m c) -> a -> m c infixr 1 #
Left-to-right composition of Kleisli arrows.
'(bs
' can be understood as the >=>
cs) ado
expression
do b <- bs a cs b
forM :: (Traversable t, Monad m) => t a -> (a -> m b) -> m (t b) #
class Monad m => MonadError e (m :: Type -> Type) | m -> e where #
The strategy of combining computations that can throw exceptions by bypassing bound functions from the point an exception is thrown to the point that it is handled.
Is parameterized over the type of error information and
the monad type constructor.
It is common to use
as the monad type constructor
for an error monad in which error descriptions take the form of strings.
In that case and many other common cases the resulting monad is already defined
as an instance of the Either
StringMonadError
class.
You can also define your own error type and/or use a monad type constructor
other than
or Either
String
.
In these cases you will have to explicitly define instances of the Either
IOError
MonadError
class.
(If you are using the deprecated Control.Monad.Error or
Control.Monad.Trans.Error, you may also have to define an Error
instance.)
throwError :: e -> m a #
Is used within a monadic computation to begin exception processing.
catchError :: m a -> (e -> m a) -> m a #
A handler function to handle previous errors and return to normal execution. A common idiom is:
do { action1; action2; action3 } `catchError` handler
where the action
functions can call throwError
.
Note that handler
and the do-block must have the same return type.
Instances
lift :: (MonadTrans t, Monad m) => m a -> t m a #
Lift a computation from the argument monad to the constructed monad.
Case analysis for the Bool
type.
evaluates to bool
x y px
when p
is False
, and evaluates to y
when p
is True
.
This is equivalent to if p then y else x
; that is, one can
think of it as an if-then-else construct with its arguments
reordered.
Examples
Basic usage:
>>>
bool "foo" "bar" True
"bar">>>
bool "foo" "bar" False
"foo"
Confirm that
and bool
x y pif p then y else x
are
equivalent:
>>>
let p = True; x = "bar"; y = "foo"
>>>
bool x y p == if p then y else x
True>>>
let p = False
>>>
bool x y p == if p then y else x
True
Since: base-4.7.0.0
sequenceA_ :: (Foldable t, Applicative f) => t (f a) -> f () #
Evaluate each action in the structure from left to right, and
ignore the results. For a version that doesn't ignore the results
see sequenceA
.
sequenceA_
is just like sequence_
, but generalised to Applicative
actions.
Examples
Basic usage:
>>>
sequenceA_ [print "Hello", print "world", print "!"]
"Hello" "world" "!"
intercalate :: [a] -> [[a]] -> [a] #
intercalate
xs xss
is equivalent to (
.
It inserts the list concat
(intersperse
xs xss))xs
in between the lists in xss
and concatenates the
result.
>>>
intercalate ", " ["Lorem", "ipsum", "dolor"]
"Lorem, ipsum, dolor"
isSuffixOf :: Eq a => [a] -> [a] -> Bool #
The isSuffixOf
function takes two lists and returns True
iff
the first list is a suffix of the second. The second list must be
finite.
>>>
"ld!" `isSuffixOf` "Hello World!"
True
>>>
"World" `isSuffixOf` "Hello World!"
False
isPrefixOf :: Eq a => [a] -> [a] -> Bool #
\(\mathcal{O}(\min(m,n))\). The isPrefixOf
function takes two lists and
returns True
iff the first list is a prefix of the second.
>>>
"Hello" `isPrefixOf` "Hello World!"
True
>>>
"Hello" `isPrefixOf` "Wello Horld!"
False
fromJust :: HasCallStack => Maybe a -> a #
fromMaybe :: a -> Maybe a -> a #
The fromMaybe
function takes a default value and a Maybe
value. If the Maybe
is Nothing
, it returns the default value;
otherwise, it returns the value contained in the Maybe
.
Examples
Basic usage:
>>>
fromMaybe "" (Just "Hello, World!")
"Hello, World!"
>>>
fromMaybe "" Nothing
""
Read an integer from a string using readMaybe
. If we fail to
parse an integer, we want to return 0
by default:
>>>
import Text.Read ( readMaybe )
>>>
fromMaybe 0 (readMaybe "5")
5>>>
fromMaybe 0 (readMaybe "")
0
maybeToList :: Maybe a -> [a] #
The maybeToList
function returns an empty list when given
Nothing
or a singleton list when given Just
.
Examples
Basic usage:
>>>
maybeToList (Just 7)
[7]
>>>
maybeToList Nothing
[]
One can use maybeToList
to avoid pattern matching when combined
with a function that (safely) works on lists:
>>>
import Text.Read ( readMaybe )
>>>
sum $ maybeToList (readMaybe "3")
3>>>
sum $ maybeToList (readMaybe "")
0
maybe :: b -> (a -> b) -> Maybe a -> b #
The maybe
function takes a default value, a function, and a Maybe
value. If the Maybe
value is Nothing
, the function returns the
default value. Otherwise, it applies the function to the value inside
the Just
and returns the result.
Examples
Basic usage:
>>>
maybe False odd (Just 3)
True
>>>
maybe False odd Nothing
False
Read an integer from a string using readMaybe
. If we succeed,
return twice the integer; that is, apply (*2)
to it. If instead
we fail to parse an integer, return 0
by default:
>>>
import Text.Read ( readMaybe )
>>>
maybe 0 (*2) (readMaybe "5")
10>>>
maybe 0 (*2) (readMaybe "")
0
Apply show
to a Maybe Int
. If we have Just n
, we want to show
the underlying Int
n
. But if we have Nothing
, we return the
empty string instead of (for example) "Nothing":
>>>
maybe "" show (Just 5)
"5">>>
maybe "" show Nothing
""
A local time together with a time zone.
There is no Eq
instance for ZonedTime
.
If you want to compare local times, use zonedTimeToLocalTime
.
If you want to compare absolute times, use zonedTimeToUTC
.
Instances
FromJSON ZonedTime | Supported string formats:
The first space may instead be a |
Defined in Data.Aeson.Types.FromJSON | |
FromJSONKey ZonedTime | |
ToJSON ZonedTime | |
ToJSONKey ZonedTime | |
Defined in Data.Aeson.Types.ToJSON | |
Data ZonedTime | |
Defined in Data.Time.LocalTime.Internal.ZonedTime gfoldl :: (forall d b. Data d => c (d -> b) -> d -> c b) -> (forall g. g -> c g) -> ZonedTime -> c ZonedTime # gunfold :: (forall b r. Data b => c (b -> r) -> c r) -> (forall r. r -> c r) -> Constr -> c ZonedTime # toConstr :: ZonedTime -> Constr # dataTypeOf :: ZonedTime -> DataType # dataCast1 :: Typeable t => (forall d. Data d => c (t d)) -> Maybe (c ZonedTime) # dataCast2 :: Typeable t => (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c ZonedTime) # gmapT :: (forall b. Data b => b -> b) -> ZonedTime -> ZonedTime # gmapQl :: (r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> ZonedTime -> r # gmapQr :: forall r r'. (r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> ZonedTime -> r # gmapQ :: (forall d. Data d => d -> u) -> ZonedTime -> [u] # gmapQi :: Int -> (forall d. Data d => d -> u) -> ZonedTime -> u # gmapM :: Monad m => (forall d. Data d => d -> m d) -> ZonedTime -> m ZonedTime # gmapMp :: MonadPlus m => (forall d. Data d => d -> m d) -> ZonedTime -> m ZonedTime # gmapMo :: MonadPlus m => (forall d. Data d => d -> m d) -> ZonedTime -> m ZonedTime # | |
Show ZonedTime | For the time zone, this only shows the name, or offset if the name is empty. |
NFData ZonedTime | |
Defined in Data.Time.LocalTime.Internal.ZonedTime |
formatTime :: FormatTime t => TimeLocale -> String -> t -> String #
Substitute various time-related information for each %-code in the string, as per formatCharacter
.
The general form is %<modifier><width><alternate><specifier>
, where <modifier>
, <width>
, and <alternate>
are optional.
<modifier>
glibc-style modifiers can be used before the specifier (here marked as z
):
%-z
- no padding
%_z
- pad with spaces
%0z
- pad with zeros
%^z
- convert to upper case
%#z
- convert to lower case (consistently, unlike glibc)
<width>
Width digits can also be used after any modifiers and before the specifier (here marked as z
), for example:
%4z
- pad to 4 characters (with default padding character)
%_12z
- pad with spaces to 12 characters
<alternate>
An optional E
character indicates an alternate formatting. Currently this only affects %Z
and %z
.
%Ez
- alternate formatting
<specifier>
For all types (note these three are done by formatTime
, not by formatCharacter
):
%%
%
%t
- tab
%n
- newline
TimeZone
For TimeZone
(and ZonedTime
and UTCTime
):
%z
- timezone offset in the format
±HHMM
%Ez
- timezone offset in the format
±HH:MM
%Z
- timezone name (or else offset in the format
±HHMM
) %EZ
- timezone name (or else offset in the format
±HH:MM
)
LocalTime
For LocalTime
(and ZonedTime
and UTCTime
and UniversalTime
):
%c
- as
dateTimeFmt
locale
(e.g.%a %b %e %H:%M:%S %Z %Y
)
TimeOfDay
For TimeOfDay
(and LocalTime
and ZonedTime
and UTCTime
and UniversalTime
):
%R
- same as
%H:%M
%T
- same as
%H:%M:%S
%X
- as
timeFmt
locale
(e.g.%H:%M:%S
) %r
- as
time12Fmt
locale
(e.g.%I:%M:%S %p
) %P
- day-half of day from (
amPm
locale
), converted to lowercase,am
,pm
%p
- day-half of day from (
amPm
locale
),AM
,PM
%H
- hour of day (24-hour), 0-padded to two chars,
00
-23
%k
- hour of day (24-hour), space-padded to two chars,
0
-23
%I
- hour of day-half (12-hour), 0-padded to two chars,
01
-12
%l
- hour of day-half (12-hour), space-padded to two chars,
1
-12
%M
- minute of hour, 0-padded to two chars,
00
-59
%S
- second of minute (without decimal part), 0-padded to two chars,
00
-60
%q
- picosecond of second, 0-padded to twelve chars,
000000000000
-999999999999
. %Q
- decimal point and fraction of second, up to 12 second decimals, without trailing zeros.
For a whole number of seconds,
%Q
omits the decimal point unless padding is specified.
UTCTime
and ZonedTime
For UTCTime
and ZonedTime
:
%s
- number of whole seconds since the Unix epoch. For times before
the Unix epoch, this is a negative number. Note that in
%s.%q
and%s%Q
the decimals are positive, not negative. For example, 0.9 seconds before the Unix epoch is formatted as-1.1
with%s%Q
.
DayOfWeek
For DayOfWeek
(and Day
and LocalTime
and ZonedTime
and UTCTime
and UniversalTime
):
%u
- day of week number for Week Date format,
1
(= Monday) -7
(= Sunday) %w
- day of week number,
0
(= Sunday) -6
(= Saturday) %a
- day of week, short form (
snd
fromwDays
locale
),Sun
-Sat
%A
- day of week, long form (
fst
fromwDays
locale
),Sunday
-Saturday
Month
For Month
(and Day
and LocalTime
and ZonedTime
and UTCTime
and UniversalTime
):
%Y
- year, no padding. Note
%0Y
and%_Y
pad to four chars %y
- year of century, 0-padded to two chars,
00
-99
%C
- century, no padding. Note
%0C
and%_C
pad to two chars %B
- month name, long form (
fst
frommonths
locale
),January
-December
%b
,%h
- month name, short form (
snd
frommonths
locale
),Jan
-Dec
%m
- month of year, 0-padded to two chars,
01
-12
Day
For Day
(and LocalTime
and ZonedTime
and UTCTime
and UniversalTime
):
%D
- same as
%m/%d/%y
%F
- same as
%Y-%m-%d
%x
- as
dateFmt
locale
(e.g.%m/%d/%y
) %d
- day of month, 0-padded to two chars,
01
-31
%e
- day of month, space-padded to two chars,
1
-31
%j
- day of year, 0-padded to three chars,
001
-366
%f
- century for Week Date format, no padding. Note
%0f
and%_f
pad to two chars %V
- week of year for Week Date format, 0-padded to two chars,
01
-53
%U
- week of year where weeks start on Sunday (as
sundayStartWeek
), 0-padded to two chars,00
-53
%W
- week of year where weeks start on Monday (as
mondayStartWeek
), 0-padded to two chars,00
-53
Duration types
The specifiers for DiffTime
, NominalDiffTime
, CalendarDiffDays
, and CalendarDiffTime
are semantically
separate from the other types.
Specifiers on negative time differences will generally be negative (think rem
rather than mod
).
NominalDiffTime
and DiffTime
Note that a "minute" of DiffTime
is simply 60 SI seconds, rather than a minute of civil time.
Use NominalDiffTime
to work with civil time, ignoring any leap seconds.
For NominalDiffTime
and DiffTime
:
%w
- total whole weeks
%d
- total whole days
%D
- whole days of week
%h
- total whole hours
%H
- whole hours of day
%m
- total whole minutes
%M
- whole minutes of hour
%s
- total whole seconds
%Es
- total seconds, with decimal point and up to <width> (default 12) decimal places, without trailing zeros.
For a whole number of seconds,
%Es
omits the decimal point unless padding is specified. %0Es
- total seconds, with decimal point and <width> (default 12) decimal places.
%S
- whole seconds of minute
%ES
- seconds of minute, with decimal point and up to <width> (default 12) decimal places, without trailing zeros.
For a whole number of seconds,
%ES
omits the decimal point unless padding is specified. %0ES
- seconds of minute as two digits, with decimal point and <width> (default 12) decimal places.
CalendarDiffDays
For CalendarDiffDays
(and CalendarDiffTime
):
%y
- total years
%b
- total months
%B
- months of year
%w
- total weeks, not including months
%d
- total days, not including months
%D
- days of week
CalendarDiffTime
For CalendarDiffTime
:
%h
- total hours, not including months
%H
- hours of day
%m
- total minutes, not including months
%M
- minutes of hour
%s
- total whole seconds, not including months
%Es
- total seconds, not including months, with decimal point and up to <width> (default 12) decimal places, without trailing zeros.
For a whole number of seconds,
%Es
omits the decimal point unless padding is specified. %0Es
- total seconds, not including months, with decimal point and <width> (default 12) decimal places.
%S
- whole seconds of minute
%ES
- seconds of minute, with decimal point and up to <width> (default 12) decimal places, without trailing zeros.
For a whole number of seconds,
%ES
omits the decimal point unless padding is specified. %0ES
- seconds of minute as two digits, with decimal point and <width> (default 12) decimal places.
:: (MonadFail m, ParseTime t) | |
=> Bool | Accept leading and trailing whitespace? |
-> TimeLocale | Time locale. |
-> String | Format string. |
-> String | Input string. |
-> m t | Return the time value, or fail if the input could not be parsed using the given format. |
Parses a time value given a format string.
Missing information will be derived from 1970-01-01 00:00 UTC (which was a Thursday).
Supports the same %-codes as formatTime
, including %-
, %_
and %0
modifiers, however padding widths are not supported.
Case is not significant in the input string.
Some variations in the input are accepted:
%z
%Ez
- accepts any of
±HHMM
or±HH:MM
. %Z
%EZ
- accepts any string of letters, or any of the formats accepted by
%z
. %0Y
- accepts exactly four digits.
%0G
- accepts exactly four digits.
%0C
- accepts exactly two digits.
%0f
- accepts exactly two digits.
For example, to parse a date in YYYY-MM-DD format, while allowing the month
and date to have optional leading zeros (notice the -
modifier used for %m
and %d
):
Prelude Data.Time> parseTimeM True defaultTimeLocale "%Y-%-m-%-d" "2010-3-04" :: Maybe Day Just 2010-03-04
data TimeLocale #
Instances
Show TimeLocale | |
Defined in Data.Time.Format.Locale showsPrec :: Int -> TimeLocale -> ShowS # show :: TimeLocale -> String # showList :: [TimeLocale] -> ShowS # | |
Eq TimeLocale | |
Defined in Data.Time.Format.Locale (==) :: TimeLocale -> TimeLocale -> Bool # (/=) :: TimeLocale -> TimeLocale -> Bool # | |
Ord TimeLocale | |
Defined in Data.Time.Format.Locale compare :: TimeLocale -> TimeLocale -> Ordering # (<) :: TimeLocale -> TimeLocale -> Bool # (<=) :: TimeLocale -> TimeLocale -> Bool # (>) :: TimeLocale -> TimeLocale -> Bool # (>=) :: TimeLocale -> TimeLocale -> Bool # max :: TimeLocale -> TimeLocale -> TimeLocale # min :: TimeLocale -> TimeLocale -> TimeLocale # |
data FeedConfiguration #
This is a data structure to keep the configuration of a feed.
FeedConfiguration | |
|
Instances
Show FeedConfiguration | |
Defined in Hakyll.Web.Feed showsPrec :: Int -> FeedConfiguration -> ShowS # show :: FeedConfiguration -> String # showList :: [FeedConfiguration] -> ShowS # | |
Eq FeedConfiguration | |
Defined in Hakyll.Web.Feed (==) :: FeedConfiguration -> FeedConfiguration -> Bool # (/=) :: FeedConfiguration -> FeedConfiguration -> Bool # |
This datatype can be used directly if you want a lower-level interface to
generate redirects. For example, if you want to redirect foo.html
to
bar.jpg
, you can use:
create ["foo.html"] $ do route idRoute compile $ makeItem $ Redirect "bar.jpg"
relativizeUrls :: Item String -> Compiler (Item String) #
Compiler form of relativizeUrls
which automatically picks the right root
path
escapeHtml :: String -> String #
HTML-escape a string
Example:
escapeHtml "Me & Dean"
Result:
"Me & Dean"
Convert a filepath to an URL starting from the site root
Example:
toUrl "foo/bar.html"
Result:
"/foo/bar.html"
This also sanitizes the URL, e.g. converting spaces into '%20'
rulesExtraDependencies :: [Dependency] -> Rules a -> Rules a #
Advanced usage: add extra dependencies to compilers. Basically this is needed when you're doing unsafe tricky stuff in the rules monad, but you still want correct builds.
A useful utility for this purpose is makePatternDependency
.
Add (or replace) routing in the current Rules
value.
This functions controls IF and WHERE the compiled results are written out
(use one of the match
functions to control WHAT content is processed and
compile
to control HOW).
See Routes
and Identifier
for
details on how output filepaths are computed.
Hint:
If there's no route attached to a rule, the compilation result is not written out.
However, the compilation result is saved to the Store
and can be loaded and used within another rule. This behavior is needed,
for example, for templates.
Examples
Rules with and without routing
-- e.g. file on disk: 'templates/post.html' -- Rule 1 (without routing) match "templates/*" $ do -- compilation result saved to store with implicit identifier, e.g. 'templates/post.html' compile templateCompiler -- Rule 2 (with routing) match "posts/**.md" $ do route $ setExtension "html" compile $ do -- load compiled result of other rule with explicit identifier. postTemplate <- loadBody "templates/post.html" pandocCompiler >>= applyTemplate postTemplate defaultContext
Note that we don't set a route in the first rule to avoid writing out our
compiled templates.
However, we can still load
(or
loadBody
) the compiled templates to apply them in a
second rule.
The content for templateCompiler
comes implicitly from the
matched template files on disk. We don't have to pass that content around
manually. See match
and compile
for details.
To control where a compilation result will be written out (as done in the second
rule), use routing functions like setExtension
.
See Hakyll.Web.Template for examples of templates and the templating syntax.
Add (or replace) the given compilation steps within the given
Compiler
value to the current Rules
value.
This functions controls HOW the content within a rule is processed (use one
of the match
functions to control WHAT content is processed).
The compilation result is saved to the Store
under an
implicit identifier.
See Identifier
for details.
If there's routing attached to the rule where this function is used, the
compilation result is also written out to a file according to that route.
See route
and Routes
for details.
Examples
Compile Markdown to HTML
-- Select all Markdown files in 'posts' directory match "posts/**.md" $ do route $ setExtension "html" -- use pandoc to transform Markdown to HTML in a single step compile pandocCompiler
Note how we set the content to be processed with
pandocCompiler
. The content comes implicitly from the
matched Markdown files on disk. We don't have to pass that content around
manually. Every file is processed the same way within this one rule.
To control where the compilation result will be written out, use routing
functions like setExtension
.
Here the compilation result of a file like posts/hakyll.md
is written out
to posts/hakyll.html
.
Compile Markdown to HTML and embed it in a template
-- Select all Markdown files in 'posts' directory match "posts/**.md" $ do route $ setExtension "html" compile $ pandocCompiler >>= loadAndApplyTemplate "templates/post.html" defaultContext -- To Hakyll templates are just plain files that have to be processed -- and placed into the store like any other file (but without routing). -- e.g. file on disk: 'templates/post.html' match "templates/*" $ compile templateBodyCompiler
Note how a Markdown post that is compiled to HTML using
pandocCompiler
in a first step and then embedded into
a HTMl Template
in a second step by using
loadAndApplyTemplate
.
We can use templates to control the design and layout of a webpage.
A template may look as follows:
<h1>$title$</h1> $body$
See Hakyll.Web.Template to see examples of the templating syntax.
Add the given version name to the implicit identifier(s) under which the
compilation result of the given remaining Rules
value is saved to the
Store
.
See Identifier
for details.
Use this wrapper function for example when you need to compile the same source file into two or more different results, each with a different version name. The version is needed to distinguish between these different compilation results in the store, otherwise they would get the same conflicting identifier in the store.
Warning:
If you add a version name with this function, you need to supply the same name
when you load
the content from the store from
within another rule.
Examples
Compile source file into differently versioned outputs and load both
-- e.g. file on disk: 'posts/hakyll.md' -- saved with implicit identifier ('posts/hakyll.md', no-version) match "posts/*" $ do route $ setExtension "html" compile pandocCompiler -- saved with implicit identifier ('posts/hakyll.md', version 'raw') match "posts/*" $ version "raw" $ do route idRoute compile getResourceBody -- use compilation results from rules above create ["index.html"] $ do route idRoute compile $ do -- load no-version version compiledPost <- load (fromFilePath "posts/hakyll.md") -- load version 'raw' rawPost <- load . setVersion (Just "raw") $ fromFilePath "posts/hakyll.md" ...
Note how a version name is needed to distinguish the unversioned and the "raw"
version when loading the Hakyll post for the index.html
page.
To control where the compilation result will be written out, use routing
functions like idRoute
and setExtension
.
:: [Identifier] | Identifiers to assign to created content in next argument |
-> Rules () | Remaining processing parts that must create content |
-> Rules () | Resulting rule |
Assign (and thereby create) the given identifier(s) to content that has no
underlying source file on disk. That content must be created within the
compile
part of the given remaining Rules
value. The given identifier is the
id under which the compilation is saved to the Store
(in
case you want to load
it within another rule).
See Identifier
for details.
Use this function for example to create an overview page that doesn't have or need its content prepared in a file (unlike blog posts which normally have a corresponding Markdown source file on disk).
Examples
Create a webpage without an underlying source file
-- saved with implicit identifier 'index.html' to Store create ["index.html"] $ do -- compilation result is written to '<destination-directory>/index.html' route idRoute -- create content without a source file from disk compile $ makeItem ("<h1>Hello World</h1>" :: String)
Note how you can use makeItem
to create content inline
(to be processed as a Compiler
value) as if that content
was loaded from a file (as it's the case when using match
).
To control where the compilation result will be written out, use routing
functions like idRoute
.
Add a selection of which source files to process (using the
given glob pattern) to the
given remaining Rules
value.
The expanded, relative path of the matched source file on disk (relative to the
project directory configured with providerDirectory
)
becomes the identifier under which the compilation result is saved to the
Store
(in case you want to load
it
within another rule).
See Identifier
for details.
Examples
Select all markdown files within a directory (but without subdirectories)
-- Match all Markdown files in the immediate 'posts' directory -- e.g. '<project-directory>/posts/hakyll.md' -- but NOT '<project-directory>/posts/haskell/monad.md' match "posts/*.md" $ do route $ setExtension "html" compile pandocCompiler
Select all markdown files within a directory (including subdirectories recursively)
-- Match all Markdown files in the 'posts' directory and any subdirectory -- e.g. '<project-directory>/posts/hakyll.md' -- and '<project-directory>/posts/haskell/monad.md' match "posts/**.md" $ do route $ setExtension "html" compile pandocCompiler
See Pattern
or search "glob patterns" online
for more details. To control where the compilation result will be written out,
use routing functions like setExtension
.
The monad used to compose rules
Instances
MonadFail Rules | |
Defined in Hakyll.Core.Rules.Internal | |
Applicative Rules | |
Functor Rules | |
Monad Rules | |
MonadMetadata Rules | |
Defined in Hakyll.Core.Rules.Internal getMetadata :: Identifier -> Rules Metadata # getMatches :: Pattern -> Rules [Identifier] # getAllMetadata :: Pattern -> Rules [(Identifier, Metadata)] # |
Describes an item that can be saved to the disk
debugCompiler :: String -> Compiler () #
Compiler for debugging purposes. Passes a message to the debug logger that is printed in verbose mode.
withErrorMessage :: String -> Compiler a -> Compiler a #
Prepend an error line to the error, if there is one. This allows you to add helpful context to error messages.
Since: hakyll-4.13.0
noResult :: String -> Compiler a #
Fail so that it is treated as non-defined in an $if()$
branching
Hakyll.Web.Template macro, and alternative
Context
s are tried
Since: hakyll-4.13.0
unsafeCompiler :: IO a -> Compiler a #
Run an IO computation without dependencies in a Compiler.
You probably want recompilingUnsafeCompiler
instead.
cached :: (Binary a, Typeable a) => String -> Compiler a -> Compiler a #
Turn on caching for a compilation value to avoid recomputing it on subsequent Hakyll runs. The storage key consists of the underlying identifier of the compiled ressource and the given name.
saveSnapshot :: (Binary a, Typeable a) => Snapshot -> Item a -> Compiler (Item a) #
Save a snapshot of the item. This function returns the same item, which
convenient for building >>=
chains.
getResourceString :: Compiler (Item String) #
Get the full contents of the matched source file as a string.
getResourceBody :: Compiler (Item String) #
Get the full contents of the matched source file as a string, but without metadata preamble, if there was one.
makeItem :: a -> Compiler (Item a) #
Create an item from the underlying identifier and a given value.
loadSnapshotBody :: (Binary a, Typeable a) => Identifier -> Snapshot -> Compiler a #
A shortcut for only requiring the body for a specific snapshot of an item
loadBody :: (Binary a, Typeable a) => Identifier -> Compiler a #
A shortcut for only requiring the body of an item.
loadBody = fmap itemBody . load
loadSnapshot :: (Binary a, Typeable a) => Identifier -> Snapshot -> Compiler (Item a) #
Require a specific snapshot of an item.
load :: (Binary a, Typeable a) => Identifier -> Compiler (Item a) #
Load an item compiled elsewhere. If the required item is not yet compiled, the build system will take care of that automatically.
withItemBody :: (a -> Compiler b) -> Item a -> Compiler (Item b) #
Perform a compiler action on the item body. This is the same as traverse
,
but looks less intimidating.
withItemBody = traverse
itemSetBody :: a -> Item b -> Item a #
Item | |
|
Instances
Foldable Item | |
Defined in Hakyll.Core.Item fold :: Monoid m => Item m -> m # foldMap :: Monoid m => (a -> m) -> Item a -> m # foldMap' :: Monoid m => (a -> m) -> Item a -> m # foldr :: (a -> b -> b) -> b -> Item a -> b # foldr' :: (a -> b -> b) -> b -> Item a -> b # foldl :: (b -> a -> b) -> b -> Item a -> b # foldl' :: (b -> a -> b) -> b -> Item a -> b # foldr1 :: (a -> a -> a) -> Item a -> a # foldl1 :: (a -> a -> a) -> Item a -> a # elem :: Eq a => a -> Item a -> Bool # maximum :: Ord a => Item a -> a # | |
Traversable Item | |
Functor Item | |
Show a => Show (Item a) | |
Binary a => Binary (Item a) | |
FromValue (Item a) a Source # | |
Defined in Hakyllbars.Context fromValue :: ContextValue a -> TemplateRunner a (Item a) Source # | |
IntoValue (Item a) a Source # | |
Defined in Hakyllbars.Context intoValue :: Item a -> ContextValue a Source # |
Whilst compiling an item, it possible to save multiple snapshots of it, and not just the final result.
A monad which lets you compile items and takes care of dependency tracking for you.
Instances
Compose two routes where the first route is applied before the second.
So f `composeRoutes` g
is more or less equivalent with g . f
.
Warning: If the first route fails (e.g. when using matchRoute
), Hakyll will
not apply the second route (if you need Hakyll to try the second route,
use <>
on Routes
instead).
Examples
Route that applies two transformations
-- e.g. file on disk: '<project-directory>/posts/hakyll.md' -- 'hakyll.md' source file implicitly gets filepath as identifier: -- 'posts/hakyll.md' match "posts/*" $ do -- compilation result is written to '<destination-directory>/hakyll.html' route $ gsubRoute "posts/" (const "") `composeRoutes` setExtension "html" compile pandocCompiler
The identifier here is that of the underlying item being processed and is
interpreted as an destination filepath.
See Identifier
for details.
Note how we first remove the "posts/" substring from that destination filepath
with gsubRoute
and then replace the extension with setExtension
.
Wrapper function around other route construction functions to get access to the metadata (of the underlying item being processed) and use that for the destination filepath construction. Warning: you have to __ensure that the accessed metadata fields actually exists__.
Examples
Route that uses a custom slug markdown metadata field
To create a search engine optimized yet human-readable url, we can introduce a slug metadata field to our files, e.g. like in the following Markdown file: 'posts/hakyll.md'
--- title: Hakyll Post slug: awesome-post ... --- In this blog post we learn about Hakyll ...
Then we can construct a route whose destination filepath is based on that field:
match "posts/*" $ do -- compilation result is written to '<destination-directory>/awesome-post.html' route $ metadataRoute $ \meta -> constRoute $ fromJust (lookupString "slug" meta) <> ".html" compile pandocCompiler
Note how we wrap metadataRoute
around the constRoute
function and how the
slug is looked up from the markdown field to construct the destination filepath.
You can use helper functions like lookupString
to access
a specific metadata field.
:: String | Pattern to repeatedly match against in the underlying identifier |
-> (String -> String) | Replacement function to apply to the matched substrings |
-> Routes | Resulting route |
Create a "substituting" route that searches for substrings (in the
underlying identifier) that match the given pattern and transforms them
according to the given replacement function.
The identifier here is that of the underlying item being processed and is
interpreted as an destination filepath. It's normally the filepath of the
source file being processed.
See Identifier
for details.
Hint: The name "gsub" comes from a similar function in [R](https://www.r-project.org) and can be read as "globally substituting" (globally in the Unix sense of repeated, not just once).
Examples
Route that replaces part of the filepath
-- e.g. file on disk: '<project-directory>/posts/hakyll.md' -- 'hakyll.md' source file implicitly gets filepath as identifier: -- 'posts/hakyll.md' match "posts/*" $ do -- compilation result is written to '<destination-directory>/haskell/hakyll.md' route $ gsubRoute "posts/" (const "haskell/") compile getResourceBody
Note that "posts/" is replaced with "haskell/" in the destination filepath.
Route that removes part of the filepath
-- implicitly gets identifier: 'tags/rss/bar.xml' create ["tags/rss/bar.xml"] $ do -- compilation result is written to '<destination-directory>/tags/bar.xml' route $ gsubRoute "rss/" (const "") compile ...
Note that "rss/" is removed from the destination filepath.
constRoute :: FilePath -> Routes #
Create a route that writes the compiled item to the given destination filepath (ignoring any identifier or other data about the item being processed). Warning: you should __use a specific destination path only for a single file in a single compilation rule__. Otherwise it's unclear which of the contents should be written to that route.
Examples
Route to a specific filepath
-- implicitly gets identifier: 'main' (ignored on next line) create ["main"] $ do -- compilation result is written to '<destination-directory>/index.html' route $ constRoute "index.html" compile $ makeItem ("<h1>Hello World</h1>" :: String)
:: (Identifier -> FilePath) | Destination filepath construction function |
-> Routes | Resulting route |
Create a route where the destination filepath is built with the given
construction function. The provided identifier for that function is normally the
filepath of the source file being processed.
See Identifier
for details.
Examples
Route that appends a custom extension
-- e.g. file on disk: '<project-directory>/posts/hakyll.md' -- 'hakyll.md' source file implicitly gets filepath as identifier: -- 'posts/hakyll.md' match "posts/*" $ do -- compilation result is written to '<destination-directory>/posts/hakyll.md.html' route $ customRoute ((<> ".html") . toFilePath) compile pandocCompiler
Note that the last part of the destination filepath becomes .md.html
matchRoute :: Pattern -> Routes -> Routes #
Apply the route if the identifier matches the given pattern, fail otherwise
setExtension :: String -> Routes #
Create a route like idRoute
that interprets the identifier (of the item
being processed) as the destination filepath but also sets (or replaces) the
extension suffix of that path. This identifier is normally the filepath of the
source file being processed.
See Identifier
for details.
Examples
Route with an existing extension
-- e.g. file on disk: '<project-directory>/posts/hakyll.md' -- 'hakyll.md' source file implicitly gets filepath as identifier: -- 'posts/hakyll.md' match "posts/*" $ do -- compilation result is written to '<destination-directory>/posts/hakyll.html' route (setExtension "html") compile pandocCompiler
Route without an existing extension
-- implicitly gets identifier: 'about' create ["about"] $ do -- compilation result is written to '<destination-directory>/about.html' route (setExtension "html") compile $ makeItem ("Hello world" :: String)
An "identity" route that interprets the identifier (of the item being
processed) as the destination filepath. This identifier is normally the
filepath of the source file being processed.
See Identifier
for details.
Examples
Route when using match
-- e.g. file on disk: '<project-directory>/posts/hakyll.md' -- 'hakyll.md' source file implicitly gets filepath as identifier: -- 'posts/hakyll.md' match "posts/*" $ do -- compilation result is written to '<destination-directory>/posts/hakyll.md' route idRoute compile getResourceBody
makePatternDependency :: MonadMetadata m => Pattern -> m Dependency #
getMatches :: MonadMetadata m => Pattern -> m [Identifier] #
getMetadata :: MonadMetadata m => Identifier -> m Metadata #
data Dependency #
Instances
Show Dependency | |
Defined in Hakyll.Core.Dependencies showsPrec :: Int -> Dependency -> ShowS # show :: Dependency -> String # showList :: [Dependency] -> ShowS # | |
Binary Dependency | |
Defined in Hakyll.Core.Dependencies |
(.||.) :: Pattern -> Pattern -> Pattern infixr 2 #
||
for patterns: the given identifier must match any subterm
(.&&.) :: Pattern -> Pattern -> Pattern infixr 3 #
&&
for patterns: the given identifier must match both subterms
hasNoVersion :: Pattern #
Match only if the identifier has no version set, e.g.
"foo/*.markdown" .&&. hasNoVersion
hasVersion :: String -> Pattern #
Specify a version, e.g.
"foo/*.markdown" .&&. hasVersion "pdf"
fromList :: [Identifier] -> Pattern #
Create a Pattern
from a list of Identifier
s it should match.
Warning: use this carefully with hasNoVersion
and hasVersion
. The
Identifier
s in the list already have versions assigned, and the pattern
will then only match the intersection of both versions.
A more concrete example,
fromList ["foo.markdown"] .&&. hasVersion "pdf"
will not match anything! The "foo.markdown"
Identifier
has no version
assigned, so the LHS of .&&.
will only match this Identifier
with no
version. The RHS only matches Identifier
s with version set to "pdf"
--
hence, this pattern matches nothing.
The correct way to use this is:
fromList $ map (setVersion $ Just "pdf") ["foo.markdown"]
Type that allows matching on identifiers
toFilePath :: Identifier -> FilePath #
Convert an identifier back to a relative FilePath
.
fromFilePath :: FilePath -> Identifier #
Parse an identifier from a file path string. For example,
-- e.g. file on disk: 'posts/hakyll.md' match "posts/*" $ do -- saved with implicit identifier 'posts/hakyll.md' compile pandocCompiler match "about/*" $ do compile $ do compiledPost <- load (fromFilePath "posts/hakyll.md") -- load with explicit identifier ...
data Identifier #
A key data type to identify a compiled Item
in the Store
.
Conceptually, it's a combination of a file path and a version name.
The version is used only when a file is
compiled within a rule using the version
wrapper function
(the same source file
can be compiled into several items in the store, so the version exists to distinguish
them).
Use functions like fromFilePath
, setVersion
, getMatches
to build an Identifier
.
Usage Examples
Normally, compiled items are saved to the store by Rules
with an automatic, implicit identifier
and loaded from the store by the user in another rule with a manual, explicit identifier.
Identifiers when using match.
Using match
builds an implicit identifier that corresponds to the expanded, relative path
of the source file on disk (relative to the project directory configured
with providerDirectory
):
-- e.g. file on disk: 'posts/hakyll.md' match "posts/*" $ do -- saved with implicit identifier 'posts/hakyll.md' compile pandocCompiler match "about/*" $ do compile $ do compiledPost <- load (fromFilePath "posts/hakyll.md") -- load with explicit identifier ...
Normally, the identifier is only explicitly created to pass to one of the load
functions.
Identifiers when using create.
Using create
(thereby inventing a file path with no underlying file on disk)
builds an implicit identifier that corresponds to the invented file path:
create ["index.html"] $ do -- saved with implicit identifier 'index.html' compile $ makeItem ("Hello world" :: String) match "about/*" $ do compile $ do compiledIndex <- load (fromFilePath "index.html") -- load with an explicit identifier ...
Identifiers when using versions.
With version
the same file can be compiled into several items in the store.
A version name is needed to distinguish them:
-- e.g. file on disk: 'posts/hakyll.md' match "posts/*" $ do -- saved with implicit identifier ('posts/hakyll.md', no-version) compile pandocCompiler match "posts/*" $ version "raw" $ do -- saved with implicit identifier ('posts/hakyll.md', versionraw
) compile getResourceBody match "about/*" $ do compile $ do compiledPost <- load (fromFilePath "posts/hakyll.md") -- load no-version version rawPost <- load . setVersion (Just "raw") $ fromFilePath "posts/hakyll.md" -- load versionraw
...
Use setVersion
to set (or replace) the version of an identifier like fromFilePath "posts/hakyll.md"
.
Instances
IsString Identifier | |
Defined in Hakyll.Core.Identifier fromString :: String -> Identifier # | |
Show Identifier | |
Defined in Hakyll.Core.Identifier showsPrec :: Int -> Identifier -> ShowS # show :: Identifier -> String # showList :: [Identifier] -> ShowS # | |
Binary Identifier | |
Defined in Hakyll.Core.Identifier | |
NFData Identifier | |
Defined in Hakyll.Core.Identifier rnf :: Identifier -> () # | |
Eq Identifier | |
Defined in Hakyll.Core.Identifier (==) :: Identifier -> Identifier -> Bool # (/=) :: Identifier -> Identifier -> Bool # | |
Ord Identifier | |
Defined in Hakyll.Core.Identifier compare :: Identifier -> Identifier -> Ordering # (<) :: Identifier -> Identifier -> Bool # (<=) :: Identifier -> Identifier -> Bool # (>) :: Identifier -> Identifier -> Bool # (>=) :: Identifier -> Identifier -> Bool # max :: Identifier -> Identifier -> Identifier # min :: Identifier -> Identifier -> Identifier # |
doesFileExist :: FilePath -> IO Bool #
The operation doesFileExist
returns True
if the argument file exists and is not a directory, and False
otherwise.
Copy a file with its permissions. If the destination file already exists, it is replaced atomically. Neither path may refer to an existing directory. No exceptions are thrown if the permissions could not be copied.
creates a new directory
createDirectoryIfMissing
parents dirdir
if it doesn't exist. If the first argument is True
the function will also create all parent directories if they are missing.
splitDirectories :: FilePath -> [FilePath] #
Just as splitPath
, but don't add the trailing slashes to each element.
splitDirectories "/directory/file.ext" == ["/","directory","file.ext"] splitDirectories "test/file" == ["test","file"] splitDirectories "/test/file" == ["/","test","file"] Windows: splitDirectories "C:\\test\\file" == ["C:\\", "test", "file"] Valid x => joinPath (splitDirectories x) `equalFilePath` x splitDirectories "" == [] Windows: splitDirectories "C:\\test\\\\\\file" == ["C:\\", "test", "file"] splitDirectories "/test///file" == ["/","test","file"]
(</>) :: FilePath -> FilePath -> FilePath infixr 5 #
Combine two paths with a path separator.
If the second path starts with a path separator or a drive letter, then it returns the second.
The intention is that readFile (dir
will access the same file as
</>
file)setCurrentDirectory dir; readFile file
.
Posix: "/directory" </> "file.ext" == "/directory/file.ext" Windows: "/directory" </> "file.ext" == "/directory\\file.ext" "directory" </> "/file.ext" == "/file.ext" Valid x => (takeDirectory x </> takeFileName x) `equalFilePath` x
Combined:
Posix: "/" </> "test" == "/test" Posix: "home" </> "bob" == "home/bob" Posix: "x:" </> "foo" == "x:/foo" Windows: "C:\\foo" </> "bar" == "C:\\foo\\bar" Windows: "home" </> "bob" == "home\\bob"
Not combined:
Posix: "home" </> "/bob" == "/bob" Windows: "home" </> "C:\\bob" == "C:\\bob"
Not combined (tricky):
On Windows, if a filepath starts with a single slash, it is relative to the
root of the current drive. In [1], this is (confusingly) referred to as an
absolute path.
The current behavior of </>
is to never combine these forms.
Windows: "home" </> "/bob" == "/bob" Windows: "home" </> "\\bob" == "\\bob" Windows: "C:\\home" </> "\\bob" == "\\bob"
On Windows, from [1]: "If a file name begins with only a disk designator
but not the backslash after the colon, it is interpreted as a relative path
to the current directory on the drive with the specified letter."
The current behavior of </>
is to never combine these forms.
Windows: "D:\\foo" </> "C:bar" == "C:bar" Windows: "C:\\foo" </> "C:bar" == "C:bar"
takeDirectory :: FilePath -> FilePath #
Get the directory name, move up one level.
takeDirectory "/directory/other.ext" == "/directory" isPrefixOf (takeDirectory x) x || takeDirectory x == "." takeDirectory "foo" == "." takeDirectory "/" == "/" takeDirectory "/foo" == "/" takeDirectory "/foo/bar/baz" == "/foo/bar" takeDirectory "/foo/bar/baz/" == "/foo/bar/baz" takeDirectory "foo/bar/baz" == "foo/bar" Windows: takeDirectory "foo\\bar" == "foo" Windows: takeDirectory "foo\\bar\\\\" == "foo\\bar" Windows: takeDirectory "C:\\" == "C:\\"
takeFileName :: FilePath -> FilePath #
Get the file name.
takeFileName "/directory/file.ext" == "file.ext" takeFileName "test/" == "" isSuffixOf (takeFileName x) x takeFileName x == snd (splitFileName x) Valid x => takeFileName (replaceFileName x "fred") == "fred" Valid x => takeFileName (x </> "fred") == "fred" Valid x => isRelative (takeFileName x)
splitFileName :: FilePath -> (String, String) #
Split a filename into directory and file. </>
is the inverse.
The first component will often end with a trailing slash.
splitFileName "/directory/file.ext" == ("/directory/","file.ext") Valid x => uncurry (</>) (splitFileName x) == x || fst (splitFileName x) == "./" Valid x => isValid (fst (splitFileName x)) splitFileName "file/bob.txt" == ("file/", "bob.txt") splitFileName "file/" == ("file/", "") splitFileName "bob" == ("./", "bob") Posix: splitFileName "/" == ("/","") Windows: splitFileName "c:" == ("c:","") Windows: splitFileName "\\\\?\\A:\\fred" == ("\\\\?\\A:\\","fred")
dropExtension :: FilePath -> FilePath #
Remove last extension, and the "." preceding it.
dropExtension "/directory/path.ext" == "/directory/path" dropExtension x == fst (splitExtension x)