stratosphere-1.0.0: EDSL for AWS CloudFormation
Safe HaskellNone
LanguageHaskell2010

Stratosphere

Description

This is a library for creating AWS CloudFormation templates.

CloudFormation is a system that creates AWS resources from declarative templates. One common criticism of CloudFormation is its use of JSON as the template specification language. Once you have a large number of templates, possibly including cross-references among themselves, raw JSON templates become unwieldy, and it becomes harder to confidently modify them. Stratosphere alleviates this issue by providing an Embedded Domain Specific Language (EDSL) to construct templates.

Synopsis

Introduction

The core datatype of stratosphere is the Template, which corresponds to a single CloudFormation template document. Users construct a template in a type-safe way using simple data types. The following example creates a template containing a single EC2 instance with a key pair passed in as a parameter:

instanceTemplate :: Template
instanceTemplate =
  template
  [ resource EC2Instance (
    EC2InstanceProperties $
    ec2Instance
    & eciImageId ?~ "ami-22111148"
    & eciKeyName ?~ (Ref KeyName)
    )
    & resourceDeletionPolicy ?~ Retain
  ]
  & templateDescription ?~ "Sample template"
  & templateParameters ?~
  [ parameter KeyName "AWS::EC2::KeyPair::KeyName"
    & parameterDescription ?~ "Name of an existing EC2 KeyPair to enable SSH access to the instance"
    & parameterConstraintDescription ?~ "Must be the name of an existing EC2 KeyPair."
  ]

Usage

The types in stratosphere attempt to map exactly to CloudFormation template components. For example, a template requires a set of Resources, and optionally accepts a Description, Parameters, etc. For each component of a template, there is usually a set of required arguments, and a (usually large) number of optional arguments. Each record type has a corresponding constructor function that has the required parameters as arguments.

For example, since a Template requires a set of Resources, the template constructor has Resources as an argument. Then, you can fill in the Maybe parameters using record updates.

Once a Template is created, you can either use Aeson's encode function, or use our encodeTemplate function (based on aeson-pretty) to produce a JSON ByteString. From there, you can use your favorite tool to interact with CloudFormation using the template.

($) :: (a -> b) -> a -> b infixr 0 #

($) is the function application operator.

Applying ($) to a function f and an argument x gives the same result as applying f to x directly. The definition is akin to this:

($) :: (a -> b) -> a -> b
($) f x = f x

This is id specialized from a -> a to (a -> b) -> (a -> b) which by the associativity of (->) is the same as (a -> b) -> a -> b.

On the face of it, this may appear pointless! But it's actually one of the most useful and important operators in Haskell.

The order of operations is very different between ($) and normal function application. Normal function application has precedence 10 - higher than any operator - and associates to the left. So these two definitions are equivalent:

expr = min 5 1 + 5
expr = ((min 5) 1) + 5

($) has precedence 0 (the lowest) and associates to the right, so these are equivalent:

expr = min 5 $ 1 + 5
expr = (min 5) (1 + 5)

Examples

Expand

A common use cases of ($) is to avoid parentheses in complex expressions.

For example, instead of using nested parentheses in the following Haskell function:

-- | Sum numbers in a string: strSum "100  5 -7" == 98
strSum :: String -> Int
strSum s = sum (mapMaybe readMaybe (words s))

we can deploy the function application operator:

-- | Sum numbers in a string: strSum "100  5 -7" == 98
strSum :: String -> Int
strSum s = sum $ mapMaybe readMaybe $ words s

($) is also used as a section (a partially applied operator), in order to indicate that we wish to apply some yet-unspecified function to a given value. For example, to apply the argument 5 to a list of functions:

applyFive :: [Int]
applyFive = map ($ 5) [(+1), (2^)]
>>> [6, 32]

Technical Remark (Representation Polymorphism)

Expand

($) is fully representation-polymorphic. This allows it to also be used with arguments of unlifted and even unboxed kinds, such as unboxed integers:

fastMod :: Int -> Int -> Int
fastMod (I# x) (I# m) = I# $ remInt# x m

data Text #

A space efficient, packed, unboxed Unicode text type.

Instances

Instances details
ToJSON Text 
Instance details

Defined in Data.Aeson.Types.ToJSON

ToJSONKey Text 
Instance details

Defined in Data.Aeson.Types.ToJSON

Hashable Text 
Instance details

Defined in Data.Hashable.Class

Methods

hashWithSalt :: Int -> Text -> Int #

hash :: Text -> Int #

MonoZip Text 
Instance details

Defined in Data.Containers

GrowingAppend Text 
Instance details

Defined in Data.MonoTraversable

MonoFoldable Text 
Instance details

Defined in Data.MonoTraversable

Methods

ofoldMap :: Monoid m => (Element Text -> m) -> Text -> m #

ofoldr :: (Element Text -> b -> b) -> b -> Text -> b #

ofoldl' :: (a -> Element Text -> a) -> a -> Text -> a #

otoList :: Text -> [Element Text] #

oall :: (Element Text -> Bool) -> Text -> Bool #

oany :: (Element Text -> Bool) -> Text -> Bool #

onull :: Text -> Bool #

olength :: Text -> Int #

olength64 :: Text -> Int64 #

ocompareLength :: Integral i => Text -> i -> Ordering #

otraverse_ :: Applicative f => (Element Text -> f b) -> Text -> f () #

ofor_ :: Applicative f => Text -> (Element Text -> f b) -> f () #

omapM_ :: Applicative m => (Element Text -> m ()) -> Text -> m () #

oforM_ :: Applicative m => Text -> (Element Text -> m ()) -> m () #

ofoldlM :: Monad m => (a -> Element Text -> m a) -> a -> Text -> m a #

ofoldMap1Ex :: Semigroup m => (Element Text -> m) -> Text -> m #

ofoldr1Ex :: (Element Text -> Element Text -> Element Text) -> Text -> Element Text #

ofoldl1Ex' :: (Element Text -> Element Text -> Element Text) -> Text -> Element Text #

headEx :: Text -> Element Text #

lastEx :: Text -> Element Text #

unsafeHead :: Text -> Element Text #

unsafeLast :: Text -> Element Text #

maximumByEx :: (Element Text -> Element Text -> Ordering) -> Text -> Element Text #

minimumByEx :: (Element Text -> Element Text -> Ordering) -> Text -> Element Text #

oelem :: Element Text -> Text -> Bool #

onotElem :: Element Text -> Text -> Bool #

MonoFunctor Text 
Instance details

Defined in Data.MonoTraversable

Methods

omap :: (Element Text -> Element Text) -> Text -> Text #

MonoPointed Text 
Instance details

Defined in Data.MonoTraversable

Methods

opoint :: Element Text -> Text #

MonoTraversable Text 
Instance details

Defined in Data.MonoTraversable

Methods

otraverse :: Applicative f => (Element Text -> f (Element Text)) -> Text -> f Text #

omapM :: Applicative m => (Element Text -> m (Element Text)) -> Text -> m Text #

IsSequence Text 
Instance details

Defined in Data.Sequences

Methods

fromList :: [Element Text] -> Text #

lengthIndex :: Text -> Index Text #

break :: (Element Text -> Bool) -> Text -> (Text, Text) #

span :: (Element Text -> Bool) -> Text -> (Text, Text) #

dropWhile :: (Element Text -> Bool) -> Text -> Text #

takeWhile :: (Element Text -> Bool) -> Text -> Text #

splitAt :: Index Text -> Text -> (Text, Text) #

unsafeSplitAt :: Index Text -> Text -> (Text, Text) #

take :: Index Text -> Text -> Text #

unsafeTake :: Index Text -> Text -> Text #

drop :: Index Text -> Text -> Text #

unsafeDrop :: Index Text -> Text -> Text #

dropEnd :: Index Text -> Text -> Text #

partition :: (Element Text -> Bool) -> Text -> (Text, Text) #

uncons :: Text -> Maybe (Element Text, Text) #

unsnoc :: Text -> Maybe (Text, Element Text) #

filter :: (Element Text -> Bool) -> Text -> Text #

filterM :: Monad m => (Element Text -> m Bool) -> Text -> m Text #

replicate :: Index Text -> Element Text -> Text #

replicateM :: Monad m => Index Text -> m (Element Text) -> m Text #

groupBy :: (Element Text -> Element Text -> Bool) -> Text -> [Text] #

groupAllOn :: Eq b => (Element Text -> b) -> Text -> [Text] #

subsequences :: Text -> [Text] #

permutations :: Text -> [Text] #

tailEx :: Text -> Text #

tailMay :: Text -> Maybe Text #

initEx :: Text -> Text #

initMay :: Text -> Maybe Text #

unsafeTail :: Text -> Text #

unsafeInit :: Text -> Text #

index :: Text -> Index Text -> Maybe (Element Text) #

indexEx :: Text -> Index Text -> Element Text #

unsafeIndex :: Text -> Index Text -> Element Text #

splitWhen :: (Element Text -> Bool) -> Text -> [Text] #

tails :: Text -> [Text] #

inits :: Text -> [Text] #

initTails :: Text -> [(Text, Text)] #

SemiSequence Text 
Instance details

Defined in Data.Sequences

Associated Types

type Index Text 
Instance details

Defined in Data.Sequences

type Index Text = Int
Textual Text 
Instance details

Defined in Data.Sequences

Methods

words :: Text -> [Text] #

unwords :: (Element seq ~ Text, MonoFoldable seq) => seq -> Text #

lines :: Text -> [Text] #

unlines :: (Element seq ~ Text, MonoFoldable seq) => seq -> Text #

toLower :: Text -> Text #

toUpper :: Text -> Text #

toCaseFold :: Text -> Text #

breakWord :: Text -> (Text, Text) #

breakLine :: Text -> (Text, Text) #

LazySequence Text Text 
Instance details

Defined in Data.Sequences

Utf8 Text ByteString 
Instance details

Defined in Data.Sequences

type Item Text 
Instance details

Defined in Data.Text

type Item Text = Char
type Element Text 
Instance details

Defined in Data.MonoTraversable

type Index Text 
Instance details

Defined in Data.Sequences

type Index Text = Int

(.) :: (b -> c) -> (a -> b) -> a -> c infixr 9 #

Right to left function composition.

(f . g) x = f (g x)
f . id = f = id . f

Examples

Expand
>>> map ((*2) . length) [[], [0, 1, 2], [0]]
[0,6,2]
>>> foldr (.) id [(+1), (*3), (^3)] 2
25
>>> let (...) = (.).(.) in ((*2)...(+)) 5 10
30

(&) :: a -> (a -> b) -> b infixl 1 #

& is a reverse application operator. This provides notational convenience. Its precedence is one higher than that of the forward application operator $, which allows & to be nested in $.

This is a version of flip id, where id is specialized from a -> a to (a -> b) -> (a -> b) which by the associativity of (->) is (a -> b) -> a -> b. flipping this yields a -> (a -> b) -> b which is the type signature of &

Examples

Expand
>>> 5 & (+1) & show
"6"
>>> sqrt $ [1 / n^2 | n <- [1..1000]] & sum & (*6)
3.1406380562059946

Since: base-4.8.0.0