-
Notifications
You must be signed in to change notification settings - Fork 159
/
Copy pathevaluation.fsx
211 lines (160 loc) · 7.13 KB
/
evaluation.fsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
(**
---
category: Documentation
categoryindex: 1
index: 7
---
*)
(*** condition: prepare ***)
#nowarn "211"
#I "../src/FSharp.Formatting/bin/Release/netstandard2.0"
#r "FSharp.Formatting.Common.dll"
#r "FSharp.Formatting.Markdown.dll"
#r "FSharp.Formatting.CodeFormat.dll"
#r "FSharp.Formatting.Literate.dll"
(*** condition: fsx ***)
#if FSX
#r "nuget: FSharp.Formatting,{{fsdocs-package-version}}"
#endif // FSX
(*** condition: ipynb ***)
#if IPYNB
#r "nuget: FSharp.Formatting,{{fsdocs-package-version}}"
#endif // IPYNB
(**
[](https://mybinder.org/v2/gh/fsprojects/fsharp.formatting/gh-pages?filepath={{fsdocs-source-basename}}.ipynb) 
[]({{root}}/{{fsdocs-source-basename}}.fsx) 
[]({{root}}/{{fsdocs-source-basename}}.ipynb)
# Embedding script output
For literate F# scripts, you may embed the result of running the script as part of the literate output.
This is a feature of the functions discussed in [literate programming](literate.html) and
it is implemented using the [F# Compiler service](http://fsharp.github.io/FSharp.Compiler.Service/).
## Including Console Output
To include the Console output use ``include-output``:
let test = 40 + 2
printf "A result is: %d" test
(*** include-output ***)
The script defines a variable `test` and then prints it. The console output is included
in the output.
To include the a formatted value use ``include-it``:
[ 0 .. 99 ]
(*** include-it ***)
To include the meta output of F# Interactive processing such as type signatures use `(*** include-fsi-output ***)`:
let test = 40 + 3
(*** include-fsi-output ***)
To include both console otuput and F# Interactive output blended use `(*** include-fsi-merged-output ***)`.
let test = 40 + 4
(*** include-fsi-merged-output ***)
You can use the same commands with a named snippet:
(*** include-it: test ***)
(*** include-fsi-output: test ***)
(*** include-output: test ***)
You can use the `include-value` command to format a specific value:
let value1 = [ 0 .. 50 ]
let value2 = [ 51 .. 100 ]
(*** include-value: value1 ***)
## Using AddPrinter and AddHtmlPrinter
You can use `fsi.AddPrinter`, `fsi.AddPrintTransformer` and `fsi.AddHtmlPrinter` to extend the formatting of objects.
## Emitting Raw Text
To emit raw text in F# literate scripts use the following:
(**
(*** raw ***)
Some raw text.
*)
which would emit
<pre>
Some raw text.
</pre>
directly into the document.
F# Formatting as a Library: Specifying the Evaluator and Formatting
---------------------------------------
If using F# Formatting as a library the embedding of F# output requires specifying an additional parameter to the
parsing functions discussed in [literate programming documentation](literate.html).
Assuming you have all the references in place, you can now create an instance of
`cref:T:FSharp.Formatting.Literate.Evaluation.FsiEvaluator` that represents a wrapper for F# interactive and pass it to all the
functions that parse script files or process script files:
*)
open FSharp.Formatting.Literate
open FSharp.Formatting.Literate.Evaluation
open FSharp.Formatting.Markdown
// Sample literate content
let content =
"""
let a = 10
(*** include-value:a ***)"""
// Create evaluator and parse script
let fsi = FsiEvaluator()
let doc = Literate.ParseScriptString(content, fsiEvaluator = fsi)
Literate.ToHtml(doc)
(**
When the `fsiEvaluator` parameter is specified, the script is evaluated and so you
can use additional commands such as `include-value`. When the evaluator is *not* specified,
it is not created automatically and so the functionality is not available (this way,
you won't accidentally run unexpected code!)
If you specify the `fsiEvaluator` parameter, but don't want a specific snippet to be evaluated
(because it might throw an exception, for example), you can use the `(*** do-not-eval ***)`
command.
The constructor of `cref:T:FSharp.Formatting.Literate.Evaluation.FsiEvaluator` takes command line parameters for `fsi.exe` that can
be used to specify, for example, defined symbols and other attributes for F# Interactive.
You can also subscribe to the `EvaluationFailed` event which is fired whenever the evaluation
of an expression fails. You can use that to do tests that verify that all off the code in your
documentation executes without errors.
F# Formatting as a Library: Custom formatting functions
---------------------------
As mentioned earlier, values are formatted using a simple `"%A"` formatter by default.
However, you can specify a formatting function that provides a nicer formatting for values
of certain types. For example, let's say that we would want to format F# lists such as
`[1; 2; 3]` as HTML ordered lists `<ol>`.
This can be done by calling `cref:M:FSharp.Formatting.Literate.Evaluation.FsiEvaluator.RegisterTransformation` on the `FsiEvaluator` instance:
*)
// Create evaluator & register simple formatter for lists
let fsiEvaluator = FsiEvaluator()
fsiEvaluator.RegisterTransformation(fun (o, ty, _executionCount) ->
// If the type of value is an F# list, format it nicely
if ty.IsGenericType
&& ty.GetGenericTypeDefinition() = typedefof<list<_>> then
let items =
// Get items as objects and create paragraph for each item
[ for it in Seq.cast<obj> (unbox o) -> [ Paragraph([ Literal(it.ToString(), None) ], None) ] ]
// Return option value (success) with ordered list
Some [ ListBlock(MarkdownListKind.Ordered, items, None) ]
else
None)
(**
The function is called with two arguments - `o` is the value to be formatted and `ty`
is the static type of the value (as inferred by the F# compiler). The sample checks
that the type of the value is a list (containing values of any type) and then it
casts all values in the list to `obj` (for simplicity). Then we generate Markdown
blocks representing an ordered list. This means that the code will work for both
LaTeX and HTML formatting - but if you only need one, you can simply produce HTML and
embed it in `InlineHtmlBlock`.
To use the new `FsiEvaluator`, we can use the same style as earlier. This time, we format
a simple list containing strings:
*)
let listy =
"""
### Formatting demo
let test = ["one";"two";"three"]
(*** include-value:test ***)"""
let docOl = Literate.ParseScriptString(listy, fsiEvaluator = fsiEvaluator)
Literate.ToHtml(docOl)
(**
The resulting HTML formatting of the document contains the snippet that defines `test`,
followed by a nicely formatted ordered list:
<blockquote>
<h3>Formatting demo</h3>
<table class="pre"><tr><td class="lines"><pre class="fssnip">
<span class="l">1: </span>
</pre>
</td>
<td class="snippet"><pre class="fssnip">
<span class="k">let</span> <spanclass="i">test</span> <span class="o">=</span> [<span class="s">"</span><span class="s">one</span><span class="s">"</span>;<span class="s">"</span><span class="s">two</span><span class="s">"</span>;<span class="s">"</span><span class="s">three</span><span class="s">"</span>]</pre>
</td>
</tr>
</table>
<ol>
<li><p>one</p></li>
<li><p>two</p></li>
<li><p>three</p></li>
</ol>
</blockquote>
*)