Safe Haskell | Safe-Inferred |
---|---|
Language | Haskell2010 |
Terms
format
- specific encoding of some information. SeeFormat
.document
-Text
in a specific format, e.g.,Haskell
(.hs
) file.document block
- consecutive lines of a document.Token
- a representation of a document block as aHaskell
type.Tokens
- a list ofToken
s.parser
- a function that reads a document line by line and converts it toToken
s. Example:hsToTokens
.printer
- a function that convertsTokens
to a document. Example:hsFromTokens
.tag
- a marker that affects howTokens
are parsed.- Each parser recognizes tags of a specific form.
Tags can be represented as a wrapper and a name.
E.g., in
'% LIMA_DISABLE some text'
, aTeX
tag, the wrapper is'% '
and the name is'LIMA_DISABLE some text'
.Parsers recognize the tag names that start with tag names specified in a
Config
.E.g., in the example above, a parser will recognize the _disable tag and will become disabled.
- When a parser is disabled, it copies lines verbatim into a
Disabled
Token
and doesn't recognize any tags until it finds an _enable tag.
Assumptions
The following assumptions must hold for outputs of parsers and inputs of printers:
Tokens
are in the same order as the corresponding blocks of document.Lines inside
Tokens
are reversed compared to the document. Example:Literate Haskell
document:line 1 line 2 % line 3 % line 4
Corresponding
Tokens
:[ Text {manyLines = ["line2","line 1"]}, Comment {someLines = "line 4" :| ["", "line 3"]} ]
- There are no leading or trailing empty lines inside of
Tokens
.
Synopsis
- type family Mode a b where ...
- type User = 'User
- type Internal = 'Internal
- data Config (a :: Mode') = Config {}
- def :: Default a => a
- toInternalConfig :: Config User -> Config Internal
- fromInternalConfig :: Config Internal -> Config User
- disable :: forall a. Lens' (Config a) (Mode a Text)
- enable :: forall a. Lens' (Config a) (Mode a Text)
- indent :: forall a. Lens' (Config a) (Mode a Text)
- dedent :: forall a. Lens' (Config a) (Mode a Text)
- mdHaskellCodeStart :: forall a. Lens' (Config a) (Mode a Text)
- mdHaskellCodeEnd :: forall a. Lens' (Config a) (Mode a Text)
- texHaskellCodeStart :: forall a. Lens' (Config a) (Mode a Text)
- texHaskellCodeEnd :: forall a. Lens' (Config a) (Mode a Text)
- (&) :: a -> (a -> b) -> b
- (?~) :: ASetter s t a (Maybe b) -> b -> s -> t
- data Format
- convertTo :: Format -> Format -> Config User -> Text -> Text
- showFormatExtension :: Format -> String
- showFormatName :: Format -> String
- data Token
- type Tokens = [Token]
- selectFromTokens :: Config User -> Format -> Tokens -> Text
- selectToTokens :: Config User -> Format -> Text -> Tokens
- mergeTokens :: Tokens -> Tokens
- stripTokens :: Tokens -> Tokens
- normalizeTokens :: Tokens -> Tokens
- hsFromTokens :: Config User -> Tokens -> Text
- hsFromTokens' :: Config User -> Tokens -> [Text]
- lhsFromTokens :: Config User -> Tokens -> Text
- lhsFromTokens' :: Config User -> Tokens -> [Text]
- mdFromTokens :: Config User -> Tokens -> Text
- mdFromTokens' :: Config User -> Tokens -> [Text]
- texFromTokens :: Config User -> Tokens -> Text
- texFromTokens' :: Config User -> Tokens -> [Text]
- lhsToTokens :: Config User -> Text -> Tokens
- hsToTokens :: Config User -> Text -> Tokens
- texToTokens :: Config User -> Text -> Tokens
- mdToTokens :: Config User -> Text -> Tokens
- exampleNonTexTokens' :: Tokens
- exampleNonTexTokens :: Tokens
- exampleTexTokens :: Tokens
- stripEmpties :: [Text] -> [Text]
- class Show a => PrettyPrint a where
Config
data Config (a :: Mode') Source #
Configuration of tag names.
Here are the default names.
>>>
pp (def :: Config User)
Config { _disable = Just "LIMA_DISABLE", _enable = Just "LIMA_ENABLE", _indent = Just "LIMA_INDENT", _dedent = Just "LIMA_DEDENT", _mdHaskellCodeStart = Just "```haskell", _mdHaskellCodeEnd = Just "```", _texHaskellCodeStart = Just "\\begin{code}", _texHaskellCodeEnd = Just "\\end{code}" }
It's possible to override these names.
>>>
pp ((def :: Config User) & disable ?~ "off" & enable ?~ "on" & indent ?~ "indent" & dedent ?~ "dedent")
Config { _disable = Just "off", _enable = Just "on", _indent = Just "indent", _dedent = Just "dedent", _mdHaskellCodeStart = Just "```haskell", _mdHaskellCodeEnd = Just "```", _texHaskellCodeStart = Just "\\begin{code}", _texHaskellCodeEnd = Just "\\end{code}" }
Config | |
|
Instances
Lenses
microlens
Format
showFormatExtension :: Format -> String Source #
Show a Format
as a file extension.
>>>
showFormatExtension Lhs
"lhs"
showFormatName :: Format -> String Source #
Show a Format
as a full name.
>>>
showFormatName Lhs
"Literate Haskell"
Tokens
Internal representation of a document.
A printer processes a list of Token
s one by one.
A Token
can have:
Indent |
|
Dedent |
|
Disabled | A block that should be invisible when rendered outside of
|
HaskellCode | Lines copied verbatim while a parser was in a |
Text | Lines copied verbatim while a parser was in a text block. |
Comment | Lines copied verbatim while a parser was in a comment block. |
Instances
Data Token Source # | |
Defined in Converter gfoldl :: (forall d b. Data d => c (d -> b) -> d -> c b) -> (forall g. g -> c g) -> Token -> c Token # gunfold :: (forall b r. Data b => c (b -> r) -> c r) -> (forall r. r -> c r) -> Constr -> c Token # dataTypeOf :: Token -> DataType # dataCast1 :: Typeable t => (forall d. Data d => c (t d)) -> Maybe (c Token) # dataCast2 :: Typeable t => (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c Token) # gmapT :: (forall b. Data b => b -> b) -> Token -> Token # gmapQl :: (r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> Token -> r # gmapQr :: forall r r'. (r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> Token -> r # gmapQ :: (forall d. Data d => d -> u) -> Token -> [u] # gmapQi :: Int -> (forall d. Data d => d -> u) -> Token -> u # gmapM :: Monad m => (forall d. Data d => d -> m d) -> Token -> m Token # gmapMp :: MonadPlus m => (forall d. Data d => d -> m d) -> Token -> m Token # gmapMo :: MonadPlus m => (forall d. Data d => d -> m d) -> Token -> m Token # | |
Show Token Source # | |
Eq Token Source # | |
PrettyPrint Tokens Source # | |
selectFromTokens :: Config User -> Format -> Tokens -> Text Source #
Select a printer function based on a given format.
selectToTokens :: Config User -> Format -> Text -> Tokens Source #
Select a parser function based on a given format.
mergeTokens :: Tokens -> Tokens Source #
Merge specific consecutive Tokens
.
>>>
pp exampleNonTexTokens'
[ Indent {n = 3}, Disabled {manyLines = ["-- What's the answer?"]}, Indent {n = 1}, Indent {n = 2}, Text {someLines = "- Intermediate results" :| []}, HaskellCode {manyLines = [" b = a 4"," a = const 3"]}, Dedent, HaskellCode {manyLines = ["answer = b * 14"]}, Comment {someLines = "Hello from comments," :| []}, Comment {someLines = "world!" :| []}, Text {someLines = "world!" :| ["Hello from text,"]}, Text {someLines = "here!" :| ["And from"]} ]
>>>
pp $ mergeTokens exampleNonTexTokens'
[ Indent {n = 3}, Disabled {manyLines = ["-- What's the answer?"]}, Indent {n = 1}, Indent {n = 2}, Text {someLines = "- Intermediate results" :| []}, HaskellCode {manyLines = [" b = a 4"," a = const 3"]}, Dedent, HaskellCode {manyLines = ["answer = b * 14"]}, Comment {someLines = "world!" :| ["","Hello from comments,"]}, Text {someLines = "here!" :| ["And from","","world!","Hello from text,"]} ]
stripTokens :: Tokens -> Tokens Source #
Strip empty lines an leading spaces in Tokens
.
- Remove empty lines in
Tokens
. - Shift lines in
HaskellCode
to the left by the minimal number of leading spaces in nonempty lines.
>>>
pp exampleNonTexTokens'
[ Indent {n = 3}, Disabled {manyLines = ["-- What's the answer?"]}, Indent {n = 1}, Indent {n = 2}, Text {someLines = "- Intermediate results" :| []}, HaskellCode {manyLines = [" b = a 4"," a = const 3"]}, Dedent, HaskellCode {manyLines = ["answer = b * 14"]}, Comment {someLines = "Hello from comments," :| []}, Comment {someLines = "world!" :| []}, Text {someLines = "world!" :| ["Hello from text,"]}, Text {someLines = "here!" :| ["And from"]} ]
>>>
pp $ stripTokens exampleNonTexTokens'
[ Indent {n = 3}, Disabled {manyLines = ["-- What's the answer?"]}, Indent {n = 1}, Indent {n = 2}, Text {someLines = "- Intermediate results" :| []}, HaskellCode {manyLines = ["b = a 4","a = const 3"]}, Dedent, HaskellCode {manyLines = ["answer = b * 14"]}, Comment {someLines = "Hello from comments," :| []}, Comment {someLines = "world!" :| []}, Text {someLines = "world!" :| ["Hello from text,"]}, Text {someLines = "here!" :| ["And from"]} ]
normalizeTokens :: Tokens -> Tokens Source #
mergeTokens
and stripTokens
.
>>>
pp $ normalizeTokens exampleNonTexTokens
[ Indent {n = 3}, Disabled {manyLines = ["-- What's the answer?"]}, Indent {n = 1}, Indent {n = 2}, Text {someLines = "- Intermediate results" :| []}, HaskellCode {manyLines = ["b = a 4","a = const 3"]}, Dedent, HaskellCode {manyLines = ["answer = b * 14"]}, Comment {someLines = "world!" :| ["","Hello from comments,"]}, Text {someLines = "here!" :| ["And from","","world!","Hello from text,"]} ]
Printers
hsFromTokens :: Config User -> Tokens -> Text Source #
Convert Tokens
to Haskell
code.
Rules
- Certain assumptions must hold for inputs.
These are the relations between document blocks and tokens when the default
Config
values are used.'{- LIMA_INDENT N -}'
(N
is anInt
) ~Indent
.'{- LIMA_DEDENT -}'
~Dedent
.- Lines between and including
'{- LIMA_DISABLE -}'
and'{- LIMA_ENABLE -}'
~Disabled
. Multiline comment starting with
'{-\n'
~Text
.{- line 1 -}
Multiline comment starting with
'{- '
wheretext
is nonempty text ~Comment
.{- line 1 line 2 -}
Other lines ~
HaskellCode
.a = 42
Example
>>>
pp $ hsFromTokens def exampleNonTexTokens
{- LIMA_INDENT 3 -} {- LIMA_DISABLE -} -- What's the answer? {- LIMA_ENABLE -} {- LIMA_INDENT 1 -} {- LIMA_INDENT 2 -} {- - Intermediate results -} a = const 3 b = a 4 {- LIMA_DEDENT -} answer = b * 14 {- Hello from comments, world! -} {- Hello from text, world! And from here! -}
hsFromTokens' :: Config User -> Tokens -> [Text] Source #
Convert Tokens
to Haskell
code.
Each Token
becomes a Text
in a list.
These Text
s are concatenated in hsFromTokens
.
lhsFromTokens :: Config User -> Tokens -> Text Source #
Convert Tokens
to Literate Haskell
code.
Rules
- Certain assumptions must hold for inputs.
These are the relations between document blocks and tokens when the default
Config
values are used.'% LIMA_INDENT N'
(N
is anInt
) ~Indent
.'% LIMA_DEDENT'
~Dedent
.Lines between and including
'% LIMA_DISABLE'
and'% LIMA_ENABLE'
~Disabled
.- There must be at least one nonempty line between these tags.
Consecutive lines, either empty or starting with
'% '
~Comment
.% Hello, % world! % Hello, % user!
- At least one line must have nonempty text after
'% '
- At least one line must have nonempty text after
Consecutive lines starting with
'> '
~HaskellCode
.> a4 = 4 > a2 = 2
- Other lines ~
Text
.
Example
>>>
pp $ lhsFromTokens def exampleNonTexTokens
% LIMA_INDENT 3 % LIMA_DISABLE % -- What's the answer? % LIMA_ENABLE % LIMA_INDENT 1 % LIMA_INDENT 2 - Intermediate results > a = const 3 > b = a 4 % LIMA_DEDENT > answer = b * 14 % Hello from comments, % world! Hello from text, world! And from here!
lhsFromTokens' :: Config User -> Tokens -> [Text] Source #
Convert Tokens
to Literate Haskell
code.
Each Token
becomes a Text
in a list.
These Text
s are concatenated in lhsFromTokens
.
mdFromTokens :: Config User -> Tokens -> Text Source #
Convert Tokens
to Markdown
code.
Rules
- Certain assumptions must hold for inputs.
These are the relations between document blocks and tokens when the default
Config
values are used.'<!-- LIMA_INDENT N -->'
(N
is anInt
) ~Indent
'<!-- LIMA_DEDENT -->'
~Dedent
.Multiline comment starting with
'<!-- LIMA_DISABLE\n'
and ending with'\nLIMA_ENABLE -->'
~Disabled
.<!-- LIMA_DISABLE a4 = 4 a2 = 2 LIMA_ENABLE -->
Multiline comments starting with
'<!-- {text}'
where{text}
is nonempty text ~Comment
.<!-- line 1 line 2 -->
Possibly indented block starting with
'```haskell'
and ending with'```'
~HaskellCode
.```haskell a4 = 2 ```
Other lines ~
Text
.Hello, world!
Example
>>>
pp $ mdFromTokens def exampleNonTexTokens
<!-- LIMA_INDENT 3 --> <!-- LIMA_DISABLE -- What's the answer? LIMA_ENABLE --> <!-- LIMA_INDENT 1 --> <!-- LIMA_INDENT 2 --> - Intermediate results ```haskell a = const 3 b = a 4 ``` <!-- LIMA_DEDENT --> ```haskell answer = b * 14 ``` <!-- Hello from comments, world! --> Hello from text, world! And from here!
mdFromTokens' :: Config User -> Tokens -> [Text] Source #
Convert Tokens
to Haskell
code.
Each Token
becomes a Text
in a list.
These Text
s are concatenated in mdFromTokens
.
texFromTokens :: Config User -> Tokens -> Text Source #
Convert Tokens
to TeX
code.
Rules
- Certain assumptions must hold for inputs.
These are the relations between document blocks and tokens when the default
Config
values are used.'% LIMA_INDENT N'
(N
is anInt
) ~Indent
'% LIMA_DEDENT'
~Dedent
.- Lines between and including
'% LIMA_DISABLE'
and'% LIMA_ENABLE'
~Disabled
. Consecutive lines, either empty or starting with
'% '
~Comment
.% Hello, % world! % Hello, % user!
- At least one line must have nonempty text after
'% '
- At least one line must have nonempty text after
- Lines between possibly indented tags
'\begin{code}'
and'\end{code}'
~HaskellCode
. - Other lines ~
Text
.
Example
>>>
pp $ texFromTokens def exampleTexTokens
% LIMA_DISABLE % -- What's the answer? % LIMA_ENABLE % LIMA_INDENT 1 % LIMA_INDENT 2 Intermediate results \begin{code} a = const 3 b = a 4 \end{code} % LIMA_DEDENT \begin{code} answer = b * 14 \end{code} % Hello from comments, % world! Hello from text, world!
texFromTokens' :: Config User -> Tokens -> [Text] Source #
Convert Tokens
to TeX
code.
Each Token
becomes a Text
in a list.
These Text
s are concatenated in texFromTokens
.
Parsers
lhsToTokens :: Config User -> Text -> Tokens Source #
Convert Tokens
to Markdown
code.
Inverse of lhsFromTokens
.
>>>
(lhsToTokens def $ lhsFromTokens def exampleNonTexTokens) == exampleNonTexTokens
True
hsToTokens :: Config User -> Text -> Tokens Source #
Convert Tokens
to Haskell
code.
Inverse of hsFromTokens
.
>>>
(hsToTokens def $ hsFromTokens def exampleNonTexTokens) == exampleNonTexTokens
True
texToTokens :: Config User -> Text -> Tokens Source #
Convert Tokens
to TeX
code.
Inverse of texFromTokens
.
>>>
(texToTokens def $ texFromTokens def exampleTexTokens) == exampleTexTokens
True
mdToTokens :: Config User -> Text -> Tokens Source #
Convert Tokens
to Markdown
code.
Inverse of mdFromTokens
.
>>>
(mdToTokens def $ mdFromTokens def exampleNonTexTokens) == exampleNonTexTokens
True
Examples
exampleNonTexTokens' :: Tokens Source #
Example non-TeX
Tokens
. See exampleTexTokens
.
When printed to a TeX
document, these Tokens
can't be correctly parsed.
This is because they don't have necessary tags surrounding Haskell
code blocks.
>>>
pp $ exampleNonTexTokens'
[ Indent {n = 3}, Disabled {manyLines = ["-- What's the answer?"]}, Indent {n = 1}, Indent {n = 2}, Text {someLines = "- Intermediate results" :| []}, HaskellCode {manyLines = [" b = a 4"," a = const 3"]}, Dedent, HaskellCode {manyLines = ["answer = b * 14"]}, Comment {someLines = "Hello from comments," :| []}, Comment {someLines = "world!" :| []}, Text {someLines = "world!" :| ["Hello from text,"]}, Text {someLines = "here!" :| ["And from"]} ]
exampleNonTexTokens :: Tokens Source #
Normalized exampleNonTexTokens'
.
>>>
pp $ exampleNonTexTokens
[ Indent {n = 3}, Disabled {manyLines = ["-- What's the answer?"]}, Indent {n = 1}, Indent {n = 2}, Text {someLines = "- Intermediate results" :| []}, HaskellCode {manyLines = ["b = a 4","a = const 3"]}, Dedent, HaskellCode {manyLines = ["answer = b * 14"]}, Comment {someLines = "world!" :| ["","Hello from comments,"]}, Text {someLines = "here!" :| ["And from","","world!","Hello from text,"]} ]
exampleTexTokens :: Tokens Source #
same as exampleNonTexTokens
, but with TeX
-specific tags that make Haskell
code blocks correctly parsable.
>>>
pp $ exampleTexTokens
[ Disabled {manyLines = ["-- What's the answer?"]}, Indent {n = 1}, Indent {n = 2}, Text {someLines = "\\begin{code}" :| ["","Intermediate results"]}, HaskellCode {manyLines = ["b = a 4","a = const 3"]}, Text {someLines = "\\end{code}" :| []}, Dedent, Text {someLines = "\\begin{code}" :| []}, HaskellCode {manyLines = ["answer = b * 14"]}, Text {someLines = "\\end{code}" :| []}, Comment {someLines = "world!" :| ["","Hello from comments,"]}, Text {someLines = "world!" :| ["Hello from text,"]} ]
Helpers
stripEmpties :: [Text] -> [Text] Source #
Remove empty lines from the beginning and the end of a list.
class Show a => PrettyPrint a where Source #
A class for prettyprinting data on multiple lines in haddocks.
It's not meant to be used outside of this library.