Wolfram Research

Function Repository Resource:

ReadableForm

Source Notebook

Display an expression in a format intended to maximize readability

Contributed by: Richard Hennigan (Wolfram Research)

ResourceFunction["ReadableForm"][expr]

displays a version of expr similar to InputForm[expr] that is formatted to maximize readability.

Details and Options

ResourceFunction["ReadableForm"] has the following options:
CachePersistence Automatic specifies how internal caching should be handled
CharacterEncoding "Unicode" which character encoding to use
"DynamicAlignment" False whether to use context-sensitive alignment across lines
"FormatHeads" Automatic a set of heads {h1,h2,} such that hi[] should be formatted in StandardForm
"IndentSize" 4 how many spaces to use for indenting
"InitialIndent" 0 how much additional indentation to apply to each line
PageWidth 80 the target character count for each line
PerformanceGoal "Quality" aspects of performance to try to optimize
"PrefixForm" True whether to use prefix form (f@x) when appropriate
"RealAccuracy" Automatic number of digits to the right of the decimal point to display for real numbers
"RelativeWidth" False whether to count indentation in page width
Possible settings for CachePersistence include:
None improves memory usage at the cost of speed
Full improves speed at the cost of memory usage
Automatic uses a balanced mix
The "DynamicAlignment" option is considered experimental and is currently only applied for a small set of expression types.
Specifying "InitialIndent"n will add an additional n×s spaces to the beginning of each line, where s is the value of "IndentSize".
The value for PageWidth specifies a desired target width and is not a hard limit.
The value for "RealAccuracy" can be one of the following:
Automatic real numbers are displayed using normal InputForm behavior
n a nonnegative integer specifying a maximum number of digits to display after decimal points
With the setting "RealAccuracy"n, real numbers will always display with at least one digit to the right of the decimal point. If there are no digits available, a zero will be used.
With the setting "RelativeWidth"True, the leading whitespace is not counted when determining the width of a line.

Examples

Basic Examples (2) 

View the code underlying a formatted expression:

In[1]:=
\!\(\*
GraphicsBox[
{RGBColor[0, 1, 0], Thickness[Large], RectangleBox[{0, -1}, {2, 1}], 
{RGBColor[1, 0, 0], DiskBox[{0, 0}]}, 
{RGBColor[0, 0, 1], CircleBox[{2, 0}]}, 
{RGBColor[1, 1, 0], PolygonBox[{{2, 0}, {4, 1}, {4, -1}}]}, 
{RGBColor[0.5, 0, 0.5], Arrowheads[Large], ArrowBox[
       NCache[{{4, Rational[3, 2]}, {0, Rational[3, 2]}, {0, 0}}, {{
         4, 1.5}, {0, 1.5}, {0, 0}}]], 
{GrayLevel[0], Dashing[{Small, Small}], LineBox[{{-1, 0}, {4, 0}}]}}}]\) // ResourceFunction[
 "ReadableForm"]
Out[1]=

Visually inspect properties of formatted objects:

In[2]:=
ResourceObject[
Association[
  "Name" -> "LeNet Trained on MNIST Data", "UUID" -> "050b1a0a-f43a-4c28-b7e0-72607a918467", "ResourceType" -> "NeuralNet", "Version" -> "1.16.0", "Description" -> "Identify the handwritten digit in an image", "RepositoryLocation" -> URL[
    "https://www.wolframcloud.com/objects/resourcesystem/api/1.0"], "WolframLanguageVersionRequired" -> "11.1", "ContentElements" -> {
    "ConstructionNotebook", "ConstructionNotebookExpression", "EvaluationNet", "UninitializedEvaluationNet", "EvaluationExample"}], ResourceSystemBase -> "https://www.wolframcloud.com/objects/\
resourcesystem/api/1.0"] // ResourceFunction["ReadableForm"]
Out[2]=

Scope (2) 

Input-style syntax highlighting is used:

In[3]:=
ResourceFunction["ReadableForm"][Hold[f[x_] := Table[i + 1, {i, x}]]]
Out[3]=

Use Unevaluated to prevent the expression from evaluating:

In[4]:=
ResourceFunction["ReadableForm"][Unevaluated[Echo[\!\(
\*SubsuperscriptBox[\(\[Integral]\), \(0\), \(1\)]\(
\*FractionBox[\(Log[
\*FractionBox[\(1\), \(2\)]\ \((1 + 
\*SqrtBox[\(1 + 4\ x\)])\)]\), \(x\)] \[DifferentialD]x\)\)]]]
Out[4]=

Generalizations and Extensions (2) 

ToString will preserve the whitespace:

In[5]:=
if = ResourceFunction["ReadableForm"][
TestResultObject[
Association[
   "TestClass" -> None, "TestIndex" -> 1, "TestID" -> None, "Outcome" -> "MessagesFailure", "Input" -> HoldForm[1/0], "ExpectedOutput" -> HoldForm[
DirectedInfinity[]], "ActualOutput" -> HoldForm[
DirectedInfinity[]], "ExpectedMessages" -> {}, "ActualMessages" -> {
HoldForm[
Message[
MessageName[Power, "infy"], 
HoldForm[0^(-1)]]]}, "AbsoluteTimeUsed" -> Quantity[0., "Seconds"], "CPUTimeUsed" -> Quantity[0., "Seconds"], "MemoryUsed" -> Quantity[1136, "Bytes"]]]]
Out[5]=
In[6]:=
ToString[if]
Out[6]=

CopyToClipboard will also preserve much of the formatting:

In[7]:=
CopyToClipboard[if];
Paste[]

Options (20) 

CachePersistence (3) 

With CachePersistenceNone, ReadableForm will not use any caching, which reduces overall memory usage but is the slowest method:

In[8]:=
First[RepeatedTiming[
  ToString[ResourceFunction["ReadableForm"][Hold[Condition[
PositionLargest[
Pattern[RH`ReadableForm`list, 
Blank[List]]], 
AllTrue[RH`ReadableForm`list, NumericQ]] := First[
FirstPosition[RH`ReadableForm`list, 
Max[RH`ReadableForm`list]]]; Condition[
PositionLargest[
Pattern[RH`ReadableForm`list, 
Blank[List]], 
Pattern[RH`ReadableForm`n, 
Alternatives[
Blank[Integer], 
HoldPattern[UpTo][
Blank[Integer]]]]], 
AllTrue[RH`ReadableForm`list, NumericQ]] := Take[
Flatten[
Map[Position[RH`ReadableForm`list, #]& , 
DeleteDuplicates[
TakeLargest[RH`ReadableForm`list, RH`ReadableForm`n]]]], RH`ReadableForm`n]], CachePersistence -> None]]]]
Out[8]=

With the default behavior of CachePersistenceAutomatic, ReadableForm will remember some values between evaluations to gain a modest performance boost:

In[9]:=
First[RepeatedTiming[
  ToString[ResourceFunction["ReadableForm"][Hold[Condition[
PositionLargest[
Pattern[RH`ReadableForm`list, 
Blank[List]]], 
AllTrue[RH`ReadableForm`list, NumericQ]] := First[
FirstPosition[RH`ReadableForm`list, 
Max[RH`ReadableForm`list]]]; Condition[
PositionLargest[
Pattern[RH`ReadableForm`list, 
Blank[List]], 
Pattern[RH`ReadableForm`n, 
Alternatives[
Blank[Integer], 
HoldPattern[UpTo][
Blank[Integer]]]]], 
AllTrue[RH`ReadableForm`list, NumericQ]] := Take[
Flatten[
Map[Position[RH`ReadableForm`list, #]& , 
DeleteDuplicates[
TakeLargest[RH`ReadableForm`list, RH`ReadableForm`n]]]], RH`ReadableForm`n]], CachePersistence -> Automatic]]]]
Out[9]=

Using CachePersistenceFull will give the fastest performance, but the extra memory used is not released for the remainder of the kernel session:

In[10]:=
First[RepeatedTiming[
  ToString[ResourceFunction["ReadableForm"][Hold[Condition[
PositionLargest[
Pattern[RH`ReadableForm`list, 
Blank[List]]], 
AllTrue[RH`ReadableForm`list, NumericQ]] := First[
FirstPosition[RH`ReadableForm`list, 
Max[RH`ReadableForm`list]]]; Condition[
PositionLargest[
Pattern[RH`ReadableForm`list, 
Blank[List]], 
Pattern[RH`ReadableForm`n, 
Alternatives[
Blank[Integer], 
HoldPattern[UpTo][
Blank[Integer]]]]], 
AllTrue[RH`ReadableForm`list, NumericQ]] := Take[
Flatten[
Map[Position[RH`ReadableForm`list, #]& , 
DeleteDuplicates[
TakeLargest[RH`ReadableForm`list, RH`ReadableForm`n]]]], RH`ReadableForm`n]], CachePersistence -> Full]]]]
Out[10]=

DynamicAlignment (3) 

ReadableForm can adjust indentation of certain parts of code in order to obtain alignment across lines when using a monospace font. Here is a helper function to display monospaced results:

In[11]:=
showMonospace[expr_] := Style[ToString[expr], PrivateFontOptions -> {"OperatorSubstitution" -> False}, FontFamily -> "Source Code Pro"];
In[12]:=
showMonospace[
 expr = Hold[
  myFunction[] := Module[{result, anotherResult, test}, result = If[
thisThing[], 
thenDoThatThing[], 
If[
thisThing[], 
thenDoThatThing[], 
otherwiseDoSomethingElse[]]]; anotherResult = If[
thisThing[], 
thenDoThatThing[], result = If[
thisThing[], 
thenDoThatThing[], 
otherwiseDoSomethingElse[]]]; otherFunction[
      result, anotherResult, test]]]]
Out[12]=

By default, ReadableForm will only indent one step at a time:

In[13]:=
ResourceFunction["ReadableForm"][expr] // showMonospace
Out[13]=

Use the setting "DynamicAlignment"True to perform additional alignment heuristics:

In[14]:=
ResourceFunction["ReadableForm"][expr, "DynamicAlignment" -> True] // showMonospace
Out[14]=

FormatHeads (3) 

By default, some expressions are formatted in StandardForm in order to enhance readability:

In[15]:=
data = <|"Image" -> RandomImage[1, {5, 5}], "Time" -> Now, "Graphics" -> \!\(\*
GraphicsBox[
{RGBColor[0, 1, 0], Thickness[Large], RectangleBox[{0, -1}, {2, 1}], 
{RGBColor[1, 0, 0], DiskBox[{0, 0}]}, 
{RGBColor[0, 0, 1], CircleBox[{2, 0}]}, 
{RGBColor[1, 1, 0], PolygonBox[{{2, 0}, {4, 1}, {4, -1}}]}, 
{RGBColor[0.5, 0, 0.5], Arrowheads[Large], ArrowBox[
          NCache[{{4, Rational[3, 2]}, {0, Rational[3, 2]}, {0, 0}}, {{4, 1.5}, {0, 1.5}, {0, 0}}]], 
{GrayLevel[0], Dashing[{Small, Small}], LineBox[{{-1, 0}, {4, 0}}]}}}]\)|>;
ResourceFunction["ReadableForm"][data]
Out[12]=

Use "FormatHeads" to control which expressions are formatted in StandardForm:

In[16]:=
ResourceFunction["ReadableForm"][data, "FormatHeads" -> {Image, Graphics}]
Out[16]=

Use Automatic to include the defaults:

In[17]:=
ResourceFunction["ReadableForm"][data, "FormatHeads" -> {Automatic, Graphics}]
Out[17]=

IndentSize (1) 

Change the size of indentation in the output:

In[18]:=
ResourceFunction["ReadableForm"][SystemInformation["Small"], "IndentSize" -> 1, "FormatHeads" -> None]
Out[18]=

InitialIndent (1) 

Specify an amount of additional indentation to apply to every line:

In[19]:=
ResourceFunction[
 "ReadableForm"][<|
  "Test1" -> <|"Name" -> "First", "Data" -> Range[10]|>, "Test2" -> <|"Name" -> "Second", "Data" -> {}|>|>, "InitialIndent" -> 8]
Out[19]=

PageWidth (1) 

Set a desired page width to control line breaks:

In[20]:=
ResourceFunction["ReadableForm"][SystemInformation["Small"], "PageWidth" -> 60, "FormatHeads" -> None]
Out[20]=

PerformanceGoal (2) 

By default, ReadableForm will traverse expressions as deep as possible to apply formatting:

In[21]:=
RepeatedTiming[
 ToString[ResourceFunction["ReadableForm"][Unevaluated[Condition[
PositionLargest[
Pattern[list, 
Blank[List]]], 
AllTrue[list, NumericQ]] := First[
FirstPosition[list, 
Max[list]]]; Condition[
PositionLargest[
Pattern[list, 
Blank[List]], 
Pattern[n, 
Alternatives[
Blank[Integer], 
HoldPattern[UpTo][
Blank[Integer]]]]], 
AllTrue[list, NumericQ]] := Take[
Flatten[
Map[Position[list, #]& , 
DeleteDuplicates[
TakeLargest[list, n]]]], n]], CachePersistence -> None]]]
Out[21]=

With PerformanceGoal"Speed", ReadableForm traverses only deep enough to format lines and uses InputForm to handle the rest:

In[22]:=
RepeatedTiming[
 ToString[ResourceFunction["ReadableForm"][Unevaluated[Condition[
PositionLargest[
Pattern[list, 
Blank[List]]], 
AllTrue[list, NumericQ]] := First[
FirstPosition[list, 
Max[list]]]; Condition[
PositionLargest[
Pattern[list, 
Blank[List]], 
Pattern[n, 
Alternatives[
Blank[Integer], 
HoldPattern[UpTo][
Blank[Integer]]]]], 
AllTrue[list, NumericQ]] := Take[
Flatten[
Map[Position[list, #]& , 
DeleteDuplicates[
TakeLargest[list, n]]]], n]], CachePersistence -> None, PerformanceGoal -> "Speed"]]]
Out[22]=

PrefixForm (2) 

By default, ReadableForm will use Prefix formatting (f@expr) for some expressions:

In[23]:=
ResourceFunction["ReadableForm"][Unevaluated[Condition[
PositionLargest[
Pattern[list, 
Blank[List]]], 
AllTrue[list, NumericQ]] := First[
FirstPosition[list, 
Max[list]]]; Condition[
PositionLargest[
Pattern[list, 
Blank[List]], 
Pattern[n, 
Alternatives[
Blank[Integer], 
HoldPattern[UpTo][
Blank[Integer]]]]], 
AllTrue[list, NumericQ]] := Take[
Flatten[
Map[Position[list, #]& , 
DeleteDuplicates[
TakeLargest[list, n]]]], n]]]
Out[23]=

Disable Prefix formatting:

In[24]:=
ResourceFunction["ReadableForm"][Unevaluated[Condition[
PositionLargest[
Pattern[list, 
Blank[List]]], 
AllTrue[list, NumericQ]] := First[
FirstPosition[list, 
Max[list]]]; Condition[
PositionLargest[
Pattern[list, 
Blank[List]], 
Pattern[n, 
Alternatives[
Blank[Integer], 
HoldPattern[UpTo][
Blank[Integer]]]]], 
AllTrue[list, NumericQ]] := Take[
Flatten[
Map[Position[list, #]& , 
DeleteDuplicates[
TakeLargest[list, n]]]], n]], "PrefixForm" -> False]
Out[24]=

RealAccuracy (2) 

By default, ReadableForm displays real numbers with all available digits:

In[25]:=
ResourceFunction["ReadableForm"][RandomReal[1000, 5]]
Out[25]=

Specify a maximum number of digits to display:

In[26]:=
ResourceFunction["ReadableForm"][RandomReal[1000, 5], "RealAccuracy" -> 3]
Out[26]=

RelativeWidth (2) 

By default, measuring "PageWidth" per line includes the leading whitespace:

In[27]:=
expr = <|
   "Test1" -> <|"Name" -> "First", "Data" -> Range[10]|>,
   "Test2" -> <|"Name" -> "Second", "Data" -> {}|>
   |>;
ResourceFunction["ReadableForm"][expr, "IndentSize" -> 12, "PageWidth" -> 45]
Out[19]=

Set "RelativeWidth" to True if you don't want to count the leading whitespace:

In[28]:=
ResourceFunction["ReadableForm"][expr, "IndentSize" -> 12, "PageWidth" -> 45, "RelativeWidth" -> True]
Out[28]=

Applications (3) 

Copy expressions to the clipboard that will be formatted nicely when pasting into email, etc.:

In[29]:=
SystemInformation["Small"] // ResourceFunction["ReadableForm"] // CopyToClipboard;
Paste[]

Create readable log files with lots of metadata:

In[30]:=
logEvent[event_] := PutAppend[
   ResourceFunction[
    "ReadableForm"][<|"Time" -> DateString[], "Event" -> event, "Metadata" -> ResourceFunction["SessionInformation"][]|>, "FormatHeads" -> None], "log.txt"];
In[31]:=
logEvent["A thing just happened"]
In[32]:=
FilePrint["log.txt"]

ReadableForm can be used to convert a FullDefinition into a formatted package notebook. Here's an example from a resource function:

In[33]:=
defString = Block[{$ContextPath = Prepend[$ContextPath, Context[ResourceFunction["Stereogram3D"]]]}, ToString[FullDefinition[ResourceFunction["Stereogram3D"]], InputForm]];

View the default formatting:

In[34]:=
Snippet[defString, 20]
Out[34]=

Create formatted cells using ReadableForm:

In[35]:=
cells = Cases[ToExpression[defString, InputForm, HoldComplete], e : Except[Null] :> Cell[BoxData[
      ToBoxes[ResourceFunction["ReadableForm"][Unevaluated[e]]]], "Code"]];

Display in a package notebook:

In[36]:=
NotebookPut@Notebook[cells, StyleDefinitions -> "Package.nb"]
Out[36]=

Properties and Relations (1) 

For expressions that only require a single line to display, the output will be very similar to InputForm:

In[37]:=
InputForm[x/Sqrt[5] + y^2 + 1/z]
Out[37]=
In[38]:=
ResourceFunction["ReadableForm"][x/Sqrt[5] + y^2 + 1/z]
Out[38]=

Possible Issues (2) 

ReadableForm is just a formatting wrapper; it doesn't evaluate on its own:

In[39]:=
FullForm[ResourceFunction["ReadableForm"][x]]
Out[39]=

The head is not visible to InputForm:

In[40]:=
InputForm[ResourceFunction["ReadableForm"][x]]
Out[40]=

Requirements

Wolfram Language 11.3 (March 2018) or above

Resource History

Related Resources

License Information