Skip to content

Instantly share code, notes, and snippets.

@LightAndLight
Created September 22, 2021 03:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save LightAndLight/9fb9e8c7631df37b7402a6af0c43bc52 to your computer and use it in GitHub Desktop.
Save LightAndLight/9fb9e8c7631df37b7402a6af0c43bc52 to your computer and use it in GitHub Desktop.
import Data.Semigroup (stimes)
import qualified Data.List as List
import Prelude hiding (words)
data Layout a = Space | Content a
deriving (Eq, Show)
layout :: b -> (a -> b) -> Layout a -> b
layout space f c =
case c of
Space -> space
Content a -> f a
newtype Doc a = Doc { unDoc :: [Line a] }
deriving (Eq, Show)
-- | The 'Semigroup' instance for 'Doc' performs vertical concatenation
instance Semigroup (Doc a) where
Doc a <> Doc b = Doc (a <> b)
instance Monoid (Doc a) where
-- | The empty document
mempty = Doc mempty
newtype Line a = Line { unLine :: [Layout a] }
deriving (Eq, Show)
-- | The 'Semigroup' instance for 'Line' performs horizontal concatenation
instance Semigroup (Line a) where
Line a <> Line b = Line (a <> b)
instance Monoid (Line a) where
-- | The empty line
mempty = Line mempty
word :: a -> Line a
word a = Line [Content a]
space :: Line a
space = Line [Space]
-- | @words ws1 <> words ws2 = words (ws1 <> ws2)
words :: [a] -> Line a
words = Line . List.intersperse Space . fmap Content
-- | A document with a single line
line :: Line a -> Doc a
line l = Doc [l]
-- | @lines ls1 <> lines ls2 = lines (ls1 <> ls2)
lines :: [Line a] -> Doc a
lines = Doc
-- | A document with all lines indented by @n@ spaces
--
-- @indented m (indented n d) = indented (m + n) d@
indented :: Int -> Doc a -> Doc a
indented n (Doc ls) = Doc (Line . (replicate n Space <>) . unLine <$> ls)
render ::
Monoid m =>
-- | How to display a space
m ->
-- | How to display a newline
m ->
-- | How to display content
(a -> m) ->
Doc a ->
m
render space newline f = go . unDoc
where
go ls =
case ls of
[] -> mempty
Line l : ls' ->
foldMap (layout space f) l <>
case ls' of
[] -> mempty
_:_ -> newline <> go ls'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment