A modern Wadler/Leijen Prettyprinter

Overview

A modern Wadler/Leijen Prettyprinter

Kotlin notes: This README is copied largely verbatim from the Haskell package.

tl;dr

A prettyprinter/text rendering engine. Easy to use, well-documented, ANSI terminal backend exists, HTML backend is trivial to implement, no name clashes, Text-based, extensible.

") prettySig name ty = pretty name <+> prettyType ty in prettySig "example" ["Int", "Bool", "Char", "IO ()"]">
let prettyType = align . sep . zipWith (<+>) ("::" : repeat "->")
    prettySig name ty = pretty name <+> prettyType ty
in  prettySig "example" ["Int", "Bool", "Char", "IO ()"]
-- Output for wide enough formats:
example :: Int -> Bool -> Char -> IO ()

-- Output for narrow formats:
example :: Int
        -> Bool
        -> Char
        -> IO ()

Kotlin notes: No ANSI terminal backend, but a demo HTML backend is present. The code to produce the same output; validated in readmeTest:

text("->") spc text(doc) } } )) fun prettySig(name: String, vararg ty: String): DocNo { return text(name) spc prettyType(ty.toList()) } val result = prettySig("example", "Int", "Bool", "Char", "IO ()") .toStringPretty(80)">
fun prettyType(items: List<String>): DocNo = align(sep(
    items.mapWhere { where, doc -> when(where) {
        Where.FIRST -> text("::") spc text(doc)
        else -> text("->") spc text(doc)
    } }
))

fun prettySig(name: String, vararg ty: String): DocNo {
    return text(name) spc prettyType(ty.toList())
}

val result = prettySig("example", "Int", "Bool", "Char", "IO ()")
    .toStringPretty(80)

Longer; want to read

This package defines a prettyprinter to format text in a flexible and convenient way. The idea is to combine a document out of many small components, then using a layouter to convert it to an easily renderable simple document, which can then be rendered to a variety of formats, for example plain Text, or Markdown. What you are reading right now was generated by this library (see GenerateReadme.hs).

Why another prettyprinter?

Haskell, more specifically Hackage, has a zoo of Wadler/Leijen based prettyprinters already. Each of them addresses a different concern with the classic wl-pprint package. This package solves all these issues, and then some.

Text instead of String

String has exactly one use, and that’s showing Hello World in tutorials. For all other uses, Text is what people should be using. The prettyprinter uses no String definitions anywhere; using a String means an immediate conversion to the internal Text-based format.

Kotlin notes: This is not an issue in Kotlin. However, we don't have string overloading, either, so you need text("my string").

Extensive documentation

The library is stuffed with runnable examples, showing use cases for the vast majority of exported values. Many things reference related definitions, everything comes with at least a sentence explaining its purpose.

No name clashes

Many prettyprinters use the legacy API of the first Wadler/Leijen prettyprinter, which used e.g. (<$>) to separate lines, which clashes with the ubiquitous synonym for fmap that’s been in Base for ages. These definitions were either removed or renamed, so there are no name clashes with standard libraries anymore.

Annotation support

Text is not all letters and newlines. Often, we want to add more information, the simplest kind being some form of styling. An ANSI terminal supports coloring, a web browser a plethora of different formattings.

More complex uses of annotations include e.g. adding type annotations for mouse-over hovers when printing a syntax tree, adding URLs to documentation, or adding source locations to show where a certain piece of output comes from. Idris is a project that makes extensive use of such a feature.

Special care has been applied to make annotations unobtrusive, so that if you don’t need or care about them there is no overhead, neither in terms of usability nor performance.

Kotlin notes: Kotlin's type inference isn't quite as good as Haskell's. When annotations are not required, we need to be a bit more explicit and specify Doc . DocNo is an alias to make this convenient.

Extensible backends

A document can be rendered in many different ways, for many different clients. There is plain text, there is the ANSI terminal, there is the browser. Each of these speak different languages, and the backend is responsible for the translation to those languages. Backends should be readily available, or easy to implement if a custom solution is desired.

As a result, each backend requires only minimal dependencies; if you don’t want to print to an ANSI terminal for example, there is no need to have a dependency on a terminal library.

Performance

Rendering large documents should be done efficiently, and the library should make it easy to optimize common use cases for the programmer.

Open implementation

The type of documents is abstract in most of the other Wadler/Leijen prettyprinters, making it hard to impossible to write adaptors from one library to another. The type should be exposed for such purposes so it is possible to write adaptors from library to library, or each of them is doomed to live on its own small island of incompatibility. For this reason, the Doc type is fully exposed in a semi-internal module for this specific use case.

Kotlin notes: We've really tried to stick to the original layout so this is a maintainable port, but Kotlin has a simpler mechanism to mark private vs. exported, so while everything lives in internal.kt, most of that is not internal.

The prettyprinter family

The prettyprinter family of packages consists of:

  • prettyprinter is the core package. It defines the language to generate nicely laid out documents, which can then be given to renderers to display them in various ways, e.g. HTML, or plain text.
  • prettyprinter-ansi-terminal provides a renderer suitable for ANSI terminal output including colors (at the cost of a dependency more).
  • prettyprinter-compat-wl-pprint provides a drop-in compatibility layer for previous users of the wl-pprint package. Use it for easy adaption of the new prettyprinter, but don't develop anything new with it.
  • prettyprinter-compat-ansi-wl-pprint is the same, but for previous users of ansi-wl-pprint.
  • prettyprinter-compat-annotated-wl-pprint is the same, but for previous users of annotated-wl-pprint.
  • prettyprinter-convert-ansi-wl-pprint is a converter, not a drop-in replacement, for documents generated by ansi-wl-pprint. Useful for interfacing with other libraries that use the other format, like Trifecta and Optparse-Applicative.

Main differences between Kotlin and Haskell

Kotlin notes: This port only includes the core prettyprinter package. There's no direct support for ANSI, but it's expected it will be relatively trivial to write an implementation of SimpleSink object that can use any JVM terminal library. A demo of an HTML sink is included.

Some Haskellisms are replaced with Kotlinisms:

  • Differences in strings
    • While Doc.Char is preserved, it takes a one codepoint string.
    • Kotlin can't overload strings; the text function must be used.
    • None of the machinery around packing and unpacking Text is needed.
    • Haven't ported fuse; we'll see if buffered IO mitigates those issues.
  • Differences in syntax and idioms
    • Functional arguments are moved to the end.
    • The <> operator is replaced with the cat infix function.
    • The <+> operator is replaced with the spc infix function.
  • The SDS.rest properties take blocks to mimic lazy evaluation.
  • The DocNo type alias helps out Kotlin's type inference when you don't need annotations.
  • The MapWhere class handles a lot of "zip this infinite list with another offset by one" tricks
  • The doc tests are ordinary unit tests.
  • Some long Haskell names are abbreviated.
    • Sometimes Kotlin doesn't bring members into scope
    • E.g. SimpleDocStream to SDS.
    • The full names are available as type aliases.
  • The rendering mechanism is replaced with a simple imperative implementation.
    • The Doc class itself contains a number of toString variants.
  • Many Haskell lists are replaced with vararg syntactic sugar.
  • There's no great way to replicate typeclasses
    • There are some pretty functions for demonstration porpoises
    • Functor, Semigroup and Monoid instances are present for completeness.
  • This is a pure Kotlin module and doesn't do any IO.
  • It is tested to compile to the JVM, JS and Native targets.

Differences to the old Wadler/Leijen prettyprinters

The library originally started as a fork of ansi-wl-pprint until every line had been touched. The result is still in the same spirit as its predecessors, but modernized to match the current ecosystem and needs.

The most significant changes are:

  1. (<$>) is removed as an operator, since it clashes with the common alias for fmap.
  2. All but the essential <> and <+> operators were removed or replaced by ordinary names.
  3. Everything extensively documented, with references to other functions and runnable code examples.
  4. Use of Text instead of String.
  5. A fuse function to optimize often-used documents before rendering for efficiency.
  6. SimpleDoc was renamed SimpleDocStream, to contrast the new SimpleDocTree.
  7. In the ANSI backend, instead of providing an own colorization function for each color/intensity/layer combination, they have been combined in color, colorDull, bgColor, and bgColorDull functions, which can be found in the ANSI terminal specific prettyprinter-ansi-terminal package.

Historical notes

This module is based on previous work by Daan Leijen and Max Bolingbroke, who implemented and significantly extended the prettyprinter given by a paper by Phil Wadler in his 1997 paper »A Prettier Printer«, by adding lots of convenience functions, styling, and new functionality. Their package, ansi-wl-pprint is widely used in the Haskell ecosystem, and is at the time of writing maintained by Edward Kmett.

Kotlin notes: This port is a faithful translation from the version uploaded to hackage by Temper Systems.

You might also like...
 🍲Foodium is a sample food blog Android application 📱 built to demonstrate the use of Modern Android development tools - (Kotlin, Coroutines, Flow, Dagger 2/Hilt, Architecture Components, MVVM, Room, Retrofit, Moshi, Material Components).
Alligator is a modern Android navigation library that will help to organize your navigation code in clean and testable way.

Alligator Alligator is a modern Android navigation library that will help to organize your navigation code in clean and testable way. Features Any app

📒 NotyKT is a complete 💎Kotlin-stack (Backend + Android) 📱 application built to demonstrate the use of Modern development tools with best practices implementation🦸.
📒 NotyKT is a complete 💎Kotlin-stack (Backend + Android) 📱 application built to demonstrate the use of Modern development tools with best practices implementation🦸.

NotyKT 🖊️ NotyKT is the complete Kotlin-stack note taking 🖊️ application 📱 built to demonstrate a use of Kotlin programming language in server-side

 🍲Foodium is a sample food blog Android application 📱 built to demonstrate the use of Modern Android development tools - (Kotlin, Coroutines, Flow, Dagger 2/Hilt, Architecture Components, MVVM, Room, Retrofit, Moshi, Material Components). Modern About Box for an Android App
Modern About Box for an Android App

About Box A modern About Box for an Android App built on the daniel-stoneuk/material-about-library. Easily display the common items of an About Box in

:closed_umbrella: An easy way to implement modern permission instructions popup.
:closed_umbrella: An easy way to implement modern permission instructions popup.

Needs An easy way to implement modern permission instructions popup. Needs can be fully customized and showing with animations. Download Gradle Add be

🛒A Minimal Expense E-Commerce App built to demonstrate the use of modern android architecture components [Navigation, Room, MotionLayout, etc..] with MVVM Architecture. ✔
🛒A Minimal Expense E-Commerce App built to demonstrate the use of modern android architecture components [Navigation, Room, MotionLayout, etc..] with MVVM Architecture. ✔

E-Store A Simple E-Commerce App 📱 built to demonstrate the use of modern android architecture component with MVVM Architecture 🏗 . Made with love ❤️

Chat is a sample project that presents a modern, 2021 approach to Android application development.
Chat is a sample project that presents a modern, 2021 approach to Android application development.

Chat for Android Chat is a sample project that presents a modern, 2021 approach to Android application development. Screenshots 📷

A project that showcases best practices for MAD (Modern Android Development).

MAD Dictionary Is this dictionary mad? Well yes, but actually no. MAD = Modern Android Development, this app is built using the very new and very awes

Restaurant is a demo application based on modern Android application tech-stacks and MVVM architecture
Restaurant is a demo application based on modern Android application tech-stacks and MVVM architecture

Restaurant is a demo application based on modern Android application tech-stacks and MVVM architecture. Fetching data from the network via repository pattern.

Taskify - An app to manage your daily tasks and boost your productivity. Taskify is built using kotlin and follows all modern android Development practices and hence is a good learning resource for beginners
Taskify - An app to manage your daily tasks and boost your productivity. Taskify is built using kotlin and follows all modern android Development practices and hence is a good learning resource for beginners

Taskify Taskify is an app to manage your daily tasks and boost your productivity Video Introduction 📹 This is a small introduction video about Taskif

Forget about bunch of XML files for maintaining UIs. Jetpack Compose is Android’s modern toolkit for building native UI. Here is a small example to get started.
Forget about bunch of XML files for maintaining UIs. Jetpack Compose is Android’s modern toolkit for building native UI. Here is a small example to get started.

Jetpack Compose Sample Description This repository is to get started with new Jetpack Compose Toolkit for Android. By using Jetpack Compose you no nee

Modern JSON processor with readable Kotlin syntax.

Kq Modern cross-platform JSON processor with readable Kotlin syntax. cat ~/Desktop/bdb.ndjson | kq '.filter{it.bool("muted")}.sortedBy{it.long("size")

IntelliJ plugin that provides a modern and powerful byte code analyzer tool window.
IntelliJ plugin that provides a modern and powerful byte code analyzer tool window.

IntelliJ Byte Code Analyzer Plugin This IntelliJ plugin provides a modern and powerful byte code analyzer tool window. Its supports Java, Kotlin, Groo

Jetpack Compose for Desktop and Web, a modern UI framework for Kotlin that makes building performant and beautiful user interfaces easy and enjoyable.
Jetpack Compose for Desktop and Web, a modern UI framework for Kotlin that makes building performant and beautiful user interfaces easy and enjoyable.

Jetpack Compose for Desktop and Web, a modern UI framework for Kotlin that makes building performant and beautiful user interfaces easy and enjoyable.

 An offline music player android app, with modern UI and powerful features
An offline music player android app, with modern UI and powerful features

Pulse Music An offline music player android app, with modern UI and powerful features If you liked this repo, fork it and leave a STAR. Your support m

The JeTrivia is built on a modern Android Development tech stack with MVVM architecture. Kotlin, Coroutine, Flow, StateFlow, Jetpack Compose, Navigation, Room, Hilt, Retrofit2, OkHttp3, kotlinx.serialization, MockK, Truth
The JeTrivia is built on a modern Android Development tech stack with MVVM architecture. Kotlin, Coroutine, Flow, StateFlow, Jetpack Compose, Navigation, Room, Hilt, Retrofit2, OkHttp3, kotlinx.serialization, MockK, Truth

JeTrivia 🚧 In Progress 🚧 The JeTrivia application is sample based on MVVM architecture. Fetching data from the network via repository pattern and sa

A Modern Kotlin-Ktor RESTful API example. Connects to a PostgreSQL database and uses Exposed framework for database operations.
A Modern Kotlin-Ktor RESTful API example. Connects to a PostgreSQL database and uses Exposed framework for database operations.

kotlin-ktor-rest-api A Modern Kotlin-Ktor RESTful API example. Connects to a PostgreSQL database and uses Exposed framework for database operations. F

🎞 A demo movie app using Jetpack Compose and Hilt based on modern Android tech stacks.
🎞 A demo movie app using Jetpack Compose and Hilt based on modern Android tech stacks.

MovieCompose is a small demo application based on modern Android tech-stacks especially focus on Jetpack Compose UI using The Movie DB API.

Owner
Ben Samuel
Engineer at Temper Systems.
Ben Samuel
Modern Kotlin version of com.example.semitop7.FireTVStyle keyboard

ftv-style-keyboard Modern Kotlin version of com.example.semitop7.FireTVStyle keyboard Manual activation on FireTV via adb shell: adb shell ime enable

nikk 1 Oct 4, 2022
A modern JSON library for Kotlin and Java.

Moshi Moshi is a modern JSON library for Android and Java. It makes it easy to parse JSON into Java objects: String json = ...; Moshi moshi = new Mos

Square 8.7k Jan 2, 2023
requery - modern SQL based query & persistence for Java / Kotlin / Android

A light but powerful object mapping and SQL generator for Java/Kotlin/Android with RxJava and Java 8 support. Easily map to or create databases, perfo

requery 3.1k Dec 29, 2022
:fire: The powerful and easiest way to implement modern material popup menu.

PowerMenu ?? The powerful and easiest way to implement modern material popup menu. PowerMenu can be fully customized and used for popup dialogs. Downl

Jaewoong Eum 1k Dec 29, 2022
A Model-View-Presenter / Model-View-Intent library for modern Android apps

Mosby A Model-View-Presenter and Model-View-Intent library for Android apps. Dependency dependencies { compile 'com.hannesdorfmann.mosby3:mvi:3.1.1

Hannes Dorfmann 5.5k Jan 5, 2023
A lightweight Android browser with modern navigation

Lightning Browser Speed, Simplicity, Security Download Master Branch Dev Branch Features Bookmarks History Multiple search engines (Google, Bing, Yaho

Anthony Restaino 1.9k Dec 28, 2022
A Model-View-Presenter / Model-View-Intent library for modern Android apps

Mosby A Model-View-Presenter and Model-View-Intent library for Android apps. Dependency dependencies { compile 'com.hannesdorfmann.mosby3:mvi:3.1.1

Hannes Dorfmann 5.5k Dec 25, 2022
📒 NotyKT is a complete 💎Kotlin-stack (Backend + Android) 📱 application built to demonstrate the use of Modern development tools with best practices implementation🦸.

NotyKT ??️ NotyKT is the complete Kotlin-stack note taking ??️ application ?? built to demonstrate a use of Kotlin programming language in server-side

Shreyas Patil 1.4k Jan 4, 2023
Kotlin-based modern RecyclerView rendering weapon

Read this in other languages: 中文, English, Changelog Yasha Item introduction: Kotlin-based modern RecyclerView rendering weapon Item Features: No Adap

Season 514 Dec 21, 2022
📒 NotyKT is a complete 💎Kotlin-stack (Backend + Android) 📱 application built to demonstrate the use of Modern development tools with best practices implementation🦸.

NotyKT ??️ NotyKT is the complete Kotlin-stack note taking ??️ application ?? built to demonstrate a use of Kotlin programming language in server-side

Shreyas Patil 1.4k Jan 8, 2023