|Portability||semi-portable (MPTC and type families)|
This module contains most of the basic functions of this package. The data types presented here are:
- data DString
- str :: String -> DString
- rawStr :: String -> DString
- toString :: DString -> String
- size :: DString -> Maybe Int
- parens :: DString -> DString -> DString -> DString
- data Printer a
- comap :: (a -> b) -> Printer b -> Printer a
- simple :: (a -> DString) -> Printer a
- simple' :: (a -> String) -> Printer a
- inputPrinter :: (b -> a -> (DString, b)) -> b -> Printer a
- inputPrinter' :: (b -> a -> (String, b)) -> b -> Printer a
- cstr :: Printer String
- cshow :: Show a => Printer a
- class Combine a b where
- (+=+) :: Printer a -> Printer a -> Printer a
- (+-+) :: Printer a -> Printer (a, b) -> Printer (a, b)
- (+/+) :: Printer a -> Printer b -> Printer (b, a)
- (+<+) :: Printer a -> Printer (b, c) -> Printer (b, (a, c))
- combine :: (c -> (a, b)) -> Printer a -> Printer b -> Printer c
- apply :: Printer a -> a -> (String, Printer a)
- applyMany :: Printer a -> [a] -> ([String], Printer a)
- applyMany_ :: Printer a -> [a] -> [String]
- applyForever :: Monad m => Printer a -> m a -> (String -> m ()) -> m ()
- class Transform a where
DString is used for constant string output, see
DString stands for
dzen, as these strings
may change depending on the state (and that's why you
shouldn't rely on
Show, as it just uses an empty state)
String into a
DString without escaping anything.
You really don't need to use this, trust me!
DString back into a
String. Note that
(toString . rawStr) is not
would not work in some cases.
Probably you don't need to use this, unless you want
something like a static bar and nothing else.
Tries to get the number of characters of the
Nothing when there are graphical objects.
Probably you don't need to use this function.
parens open close d is equivalent to
mconcat [open, d, close].
A printer is used when the output depends on an input, so a
Printer a generates a
DString based on some input of
a (and possibly updates some internal state).
Printer that depends on the current
and on the previous inputs.
inputPrinter, but with
str, but uses the input instead of being
constant. In fact, it is defined as
Class used for combining
Note that we don't lift
Printer () and use a
plain function of type
Printer a -> Printer b
-> Printer (a,b) because that would create types such as
Printer ((),(a,((),(b,())))) instead of
We currently have the following
type Combined DString Dstring = DString type Combined DString (Printer a) = Printer a type Combined (Printer a) DString = Printer a type Combined (Printer a) (Printer b) = Printer (a,b)
For example, if
a :: DString,
b,e :: Printer Int,
c :: Printer Double and
d :: DString, then
(a +++ b +++ c +++ d +++ e) :: Printer (Int, (Double, Int))
Sometimes you want two printers having the same input,
p1 +++ p2 :: Printer (a,a) is not convenient. So
p1 +=+ p2 :: Printer a works like
+++ but gives
the same input for both printers.
+=+ but the second printer's input is a tuple.
While you may say
p1 +=+ (ds1 +++ ds2 +++ p2),
p1,p2 :: Printer a and
ds1,ds2 :: DString,
you can't say
p1 +=+ (po +++ p2) nor
(p1 +++ po) +=+ p2 where
po :: Printer b.
This operator works like
+++ but shifts the
tuple, giving you
Printer (b,a) instead of
Printer (a,b). In the example above you may
p1 +>+ po +/+ p2.
This operator works like
+/+ but the second
printer's input is a tuple. Use it like
pA1 +-+ pB +<+ pC +<+ pD +/+ pA2 :: Printer (a,(b,(c,d)))
pA2 are of type
This is a general combine function for
The outputs are always concatenated, but the inputs
are given by the supplied function.
The combining operators above are defined as:
(+++) = combine id -- restricted to Printers (+=+) = combine (\x -> ( x, x)) (+-+) = combine (\x -> (fst x, x)) (+/+) = combine (\(a,b) -> (b,a)) (+<+) = combine (\(b,(a,c)) -> (a,(b,c)))
Note also the resamblence with
comap. In fact,
if we have
comap we may define
combine f a b = comap f (a +++ b) -- pointwise combine = flip (.) (+++) . (.) . comap -- pointfree
simple we may define
comap f = combine (\i -> ((), f i)) (simple $ const mempty) -- pointwise comap = flip combine (simple $ const mempty) . ((,) () .) -- pointfree
Note that applying should be the last thing you do,
and you should never apply inside a
Printer. Doing so may cause undefined behaviour
Printer contain some internal
state. We create a fresh internal state when applying,
so applying inside them will not take their internal
state into account. You've been warned!
Apply a printer to an appropriate input, returning the output string and the new printer.
Apply a printer many times in sequence. Most of the
time you would ignore the final printer using
applyMany_, but it can be used to continue applying.
Apply a printer forever inside a monad. The first action is used as a supply of inputs while the second action receives the output before the next input is requested.
Note that your supply may be anything. For example,
IO you may use
applyForever (threadDelay 100000 >> getInfo) (hPutStrLn dzenHandle)
Transform is a specialization of
This class is used for functions that may receive
Printer a as an argument because they operate only
on their outputs and internal states (and not on the inputs).
So, whenever you see a function of type
func :: Transform a => Blah -> Bleh -> a -> a
it means that
func can be used in two ways:
func :: Blah -> Bleh -> DString -> DString func :: Blah -> Bleh -> Printer a -> Printer a -- Printer of any input!
Try to have this in mind when reading the types.
Note: There is also a non-exported
transforming the state in this class, otherwise it would
be meaningless to use a class only for
would be better to make
liftT :: (DString -> DString)
-> (Printer a -> Printer a)).
This function is
modifies the output of a