core-program-0.6.0.1: Opinionated Haskell Interoperability
Safe HaskellSafe-Inferred
LanguageHaskell2010

Core.Program

Description

Support for building command-line programs, ranging from simple tools to long-running daemons.

This is intended to be used directly:

import Core.Program

the submodules are mostly there to group documentation.

Synopsis

Executing a program

A top-level Program type giving you unified access to logging, concurrency, and more.

data Datum Source #

Carrier for spans and events while their data is being accumulated, and later sent down the telemetry channel. There is one of these in the Program monad's Context.

Instances

Instances details
Show Datum Source # 
Instance details

Defined in Core.Program.Context

Methods

showsPrec :: Int -> Datum -> ShowS #

show :: Datum -> String #

showList :: [Datum] -> ShowS #

newtype Trace Source #

Unique identifier for a trace. If your program is the top of an service stack then you can use beginTrace to generate a new idenfifier for this request or iteration. More commonly, however, you will inherit the trace identifier from the application or service which invokes this program or request handler, and you can specify it by using usingTrace.

Constructors

Trace Rope 

Instances

Instances details
IsString Trace Source # 
Instance details

Defined in Core.Program.Context

Methods

fromString :: String -> Trace #

Show Trace Source # 
Instance details

Defined in Core.Program.Context

Methods

showsPrec :: Int -> Trace -> ShowS #

show :: Trace -> String #

showList :: [Trace] -> ShowS #

Eq Trace Source # 
Instance details

Defined in Core.Program.Context

Methods

(==) :: Trace -> Trace -> Bool #

(/=) :: Trace -> Trace -> Bool #

newtype Span Source #

Unique identifier for a span. This will be generated by encloseSpan but for the case where you are continuing an inherited trace and passed the identifier of the parent span you can specify it using this constructor.

Constructors

Span Rope 

Instances

Instances details
IsString Span Source # 
Instance details

Defined in Core.Program.Context

Methods

fromString :: String -> Span #

Show Span Source # 
Instance details

Defined in Core.Program.Context

Methods

showsPrec :: Int -> Span -> ShowS #

show :: Span -> String #

showList :: [Span] -> ShowS #

Eq Span Source # 
Instance details

Defined in Core.Program.Context

Methods

(==) :: Span -> Span -> Bool #

(/=) :: Span -> Span -> Bool #

data Context τ Source #

Internal context for a running program. You access this via actions in the Program monad. The principal item here is the user-supplied top-level application data of type τ which can be retrieved with getApplicationState and updated with setApplicationState.

Instances

Instances details
Functor Context Source # 
Instance details

Defined in Core.Program.Context

Methods

fmap :: (a -> b) -> Context a -> Context b #

(<$) :: a -> Context b -> Context a #

MonadReader (Context τ) (Program τ) Source # 
Instance details

Defined in Core.Program.Context

Methods

ask :: Program τ (Context τ) #

local :: (Context τ -> Context τ) -> Program τ a -> Program τ a #

reader :: (Context τ -> a) -> Program τ a #

handleCommandLine :: Context τ -> IO (Context τ) Source #

Process the command line options and arguments. If an invalid option is encountered or a [mandatory] argument is missing, then the program will terminate here.

data Exporter Source #

Constructors

Exporter 

data Forwarder Source #

Implementation of a forwarder for structured logging of the telemetry channel.

Constructors

Forwarder 

Fields

data None Source #

A Program with no user-supplied state to be threaded throughout the computation.

The Core.Program.Execute framework makes your top-level application state available at the outer level of your process. While this is a feature that most substantial programs rely on, it is not needed for many simple tasks or when first starting out what will become a larger project.

This is effectively the unit type, but this alias is here to clearly signal a user-data type is not a part of the program semantics.

Constructors

None 

Instances

Instances details
Show None Source # 
Instance details

Defined in Core.Program.Context

Methods

showsPrec :: Int -> None -> ShowS #

show :: None -> String #

showList :: [None] -> ShowS #

Eq None Source # 
Instance details

Defined in Core.Program.Context

Methods

(==) :: None -> None -> Bool #

(/=) :: None -> None -> Bool #

configure :: Version -> τ -> Config -> IO (Context τ) Source #

Initialize the programs's execution context. This takes care of various administrative actions, including setting up output channels, parsing command-line arguments (according to the supplied configuration), and putting in place various semaphores for internal program communication. See Core.Program.Arguments for details.

This is also where you specify the initial {blank, empty, default) value for the top-level user-defined application state, if you have one. Specify None if you aren't using this feature.

data Verbosity Source #

The verbosity level of the output logging subsystem. You can override the level specified on the command-line by calling setVerbosityLevel from within the Program monad.

Constructors

Output 
Verbose

Since: 0.2.12

Debug 
Internal

Since: 0.4.6

Instances

Instances details
Show Verbosity Source # 
Instance details

Defined in Core.Program.Context

newtype Program τ α Source #

The type of a top-level program.

You would use this by writing:

module Main where

import Core.Program

main :: IO ()
main = execute program

and defining a program that is the top level of your application:

program :: Program None ()

Such actions are combinable; you can sequence them (using bind in do-notation) or run them in parallel, but basically you should need one such object at the top of your application.

Type variables

A Program has a user-supplied application state and a return type.

The first type variable, τ, is your application's state. This is an object that will be threaded through the computation and made available to your code in the Program monad. While this is a common requirement of the outer code layer in large programs, it is often not necessary in small programs or when starting new projects. You can mark that there is no top-level application state required using None and easily change it later if your needs evolve.

The return type, α, is usually unit as this effectively being called directly from main and Haskell programs have type IO (). That is, they don't return anything; I/O having already happened as side effects.

Programs in separate modules

One of the quirks of Haskell is that it is difficult to refer to code in the Main module when you've got a number of programs kicking around in a project each with a main function. One way of dealing with this is to put your top-level Program actions in a separate modules so you can refer to them from test suites and example snippets.

Interoperating with the rest of the Haskell ecosystem

The Program monad is a wrapper over IO; at any point when you need to move to another package's entry point, just use liftIO. It's re-exported by Core.System.Base for your convenience. Later, you might be interested in unlifting back to Program; see Core.Program.Unlift.

Constructors

Program (ReaderT (Context τ) IO α) 

Instances

Instances details
MonadFail (Program τ) Source # 
Instance details

Defined in Core.Program.Context

Methods

fail :: String -> Program τ a #

MonadIO (Program τ) Source # 
Instance details

Defined in Core.Program.Context

Methods

liftIO :: IO a -> Program τ a #

Applicative (Program τ) Source # 
Instance details

Defined in Core.Program.Context

Methods

pure :: a -> Program τ a #

(<*>) :: Program τ (a -> b) -> Program τ a -> Program τ b #

liftA2 :: (a -> b -> c) -> Program τ a -> Program τ b -> Program τ c #

(*>) :: Program τ a -> Program τ b -> Program τ b #

(<*) :: Program τ a -> Program τ b -> Program τ a #

Functor (Program τ) Source # 
Instance details

Defined in Core.Program.Context

Methods

fmap :: (a -> b) -> Program τ a -> Program τ b #

(<$) :: a -> Program τ b -> Program τ a #

Monad (Program τ) Source # 
Instance details

Defined in Core.Program.Context

Methods

(>>=) :: Program τ a -> (a -> Program τ b) -> Program τ b #

(>>) :: Program τ a -> Program τ b -> Program τ b #

return :: a -> Program τ a #

MonadCatch (Program τ) Source # 
Instance details

Defined in Core.Program.Context

Methods

catch :: Exception e => Program τ a -> (e -> Program τ a) -> Program τ a #

MonadMask (Program t) Source # 
Instance details

Defined in Core.Program.Context

Methods

mask :: ((forall a. Program t a -> Program t a) -> Program t b) -> Program t b #

uninterruptibleMask :: ((forall a. Program t a -> Program t a) -> Program t b) -> Program t b #

generalBracket :: Program t a -> (a -> ExitCase b -> Program t c) -> (a -> Program t b) -> Program t (b, c) #

MonadThrow (Program τ) Source # 
Instance details

Defined in Core.Program.Context

Methods

throwM :: Exception e => e -> Program τ a #

MonadReader (Context τ) (Program τ) Source # 
Instance details

Defined in Core.Program.Context

Methods

ask :: Program τ (Context τ) #

local :: (Context τ -> Context τ) -> Program τ a -> Program τ a #

reader :: (Context τ -> a) -> Program τ a #

unProgram :: Program τ α -> ReaderT (Context τ) IO α Source #

getContext :: Program τ (Context τ) Source #

Get the internal Context of the running Program. There is ordinarily no reason to use this; to access your top-level application data τ within the Context use getApplicationState.

fmapContext :: (τ1 -> τ2) -> Context τ1 -> IO (Context τ2) Source #

Map a function over the underlying user-data inside the Context, changing it from typeτ1 to τ2.

subProgram :: Context τ -> Program τ α -> IO α Source #

Run a subprogram from within a lifted IO block.

Command-line argument parsing

Including declaring what options your program accepts, generating help, and for more complex cases [sub]commands, mandatory arguments, and environment variable handling.

Logging facilities

Facilities for noting events through your program and doing debugging.

There are a few common use cases which require a bit of wrapping to use effectively. Watching files for changes and taking action in the event of a change is one.