@explorable-viz/fluid 0.11.4 → 0.12.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/README.md +22 -9
  2. package/dist/fluid/fluid/lib/graphics.fld +60 -60
  3. package/dist/fluid/fluid/lib/matrix.fld +17 -17
  4. package/dist/fluid/fluid/lib/prelude.fld +36 -35
  5. package/dist/fluid/fluid/lib/stats.fld +19 -19
  6. package/dist/fluid/shared/fluid.mjs +1044 -2141
  7. package/dist/fluid/shared/load-figure.js +1123 -2147
  8. package/dist/fluid/shared/webtest-lib.js +124 -124
  9. package/package.json +1 -1
  10. package/website/article/css/styles.css +3 -3
  11. package/website/article/fluid/1805.02474v1-10.fld +2 -2
  12. package/website/article/fluid/bar-chart-line-chart.fld +1 -1
  13. package/website/article/fluid/convolution.fld +14 -17
  14. package/website/article/fluid/dataset/scigen/_1805_02474v1_10.fld +1 -1
  15. package/website/article/fluid/methane_data.fld +1 -1
  16. package/website/article/fluid/moving-average.fld +1 -1
  17. package/website/article/fluid/non-renewables.fld +1 -1
  18. package/website/article/fluid/nonRenewables.fld +2 -2
  19. package/website/article/fluid/renewables.fld +1 -1
  20. package/website/article/fluid/scigen.fld +3 -3
  21. package/website/article/fluid/util.fld +4 -4
  22. package/.spago/aff/v7.0.0/.editorconfig +0 -13
  23. package/.spago/aff/v7.0.0/.eslintrc.json +0 -28
  24. package/.spago/aff/v7.0.0/.gitignore +0 -14
  25. package/.spago/aff/v7.0.0/.tidyrc.json +0 -10
  26. package/.spago/argonaut-codecs/v9.0.0/.editorconfig +0 -13
  27. package/.spago/argonaut-codecs/v9.0.0/.gitignore +0 -9
  28. package/.spago/argonaut-codecs/v9.0.0/.tidyrc.json +0 -10
  29. package/.spago/arrays/v7.0.0/.eslintrc.json +0 -26
  30. package/.spago/arrays/v7.0.0/.gitignore +0 -9
  31. package/.spago/console/v6.0.0/.eslintrc.json +0 -30
  32. package/.spago/console/v6.0.0/.gitignore +0 -9
  33. package/.spago/debug/v6.0.0/.eslintrc.json +0 -36
  34. package/.spago/debug/v6.0.0/.gitignore +0 -8
  35. package/.spago/enums/v6.0.0/.gitignore +0 -7
  36. package/.spago/foreign-object/v4.0.0/.eslintrc.json +0 -26
  37. package/.spago/foreign-object/v4.0.0/.gitignore +0 -8
  38. package/.spago/free/v7.0.0/.gitignore +0 -8
  39. package/.spago/graphs/v8.0.0/.gitignore +0 -7
  40. package/.spago/js-uri/v3.0.0/.eslintrc.json +0 -30
  41. package/.spago/js-uri/v3.0.0/.gitignore +0 -14
  42. package/.spago/js-uri/v3.0.0/.tidyrc.json +0 -10
  43. package/.spago/node-buffer/v8.0.0/.eslintrc.json +0 -26
  44. package/.spago/node-buffer/v8.0.0/.gitignore +0 -8
  45. package/.spago/node-child-process/v9.0.0/.eslintrc.json +0 -29
  46. package/.spago/node-child-process/v9.0.0/.gitignore +0 -8
  47. package/.spago/node-process/v10.0.0/.eslintrc.json +0 -29
  48. package/.spago/node-process/v10.0.0/.gitignore +0 -8
  49. package/.spago/node-streams/v7.0.0/.eslintrc.json +0 -29
  50. package/.spago/node-streams/v7.0.0/.gitignore +0 -8
  51. package/.spago/optparse/v5.0.0/.gitignore +0 -8
  52. package/.spago/optparse/v5.0.0/.npmrc +0 -1
  53. package/.spago/ordered-collections/v3.0.0/.gitignore +0 -8
  54. package/.spago/parallel/v6.0.0/.gitignore +0 -7
  55. package/.spago/parsing/v10.0.0/.editorconfig +0 -13
  56. package/.spago/parsing/v10.0.0/.gitignore +0 -10
  57. package/.spago/parsing/v10.0.0/.tidyoperators +0 -231
  58. package/.spago/parsing/v10.0.0/.tidyrc.json +0 -10
  59. package/.spago/prelude/v6.0.0/.eslintrc.json +0 -26
  60. package/.spago/prelude/v6.0.0/.gitignore +0 -8
  61. package/.spago/st/v6.0.0/.eslintrc.json +0 -26
  62. package/.spago/st/v6.0.0/.gitignore +0 -8
  63. package/.spago/strings/v6.0.0/.eslintrc.json +0 -26
  64. package/.spago/strings/v6.0.0/.gitignore +0 -8
  65. package/.spago/tailrec/v6.0.0/.gitignore +0 -7
  66. package/.spago/web-html/v4.0.0/.eslintrc.json +0 -29
  67. package/.spago/web-html/v4.0.0/.gitignore +0 -8
  68. package/.spago/web-xhr/v5.0.0/.eslintrc.json +0 -29
  69. package/.spago/web-xhr/v5.0.0/.gitignore +0 -8
  70. package/website/article/.DS_Store +0 -0
  71. package/website/article/dataset/.DS_Store +0 -0
package/README.md CHANGED
@@ -1,31 +1,44 @@
1
1
  ## Fluid: Language-integrated data provenance
2
2
 
3
- Fluid is an experimental programming language which integrates a bidirectional dynamic analysis to connect outputs to data sources in a fine-grained way. Fluid is implemented in PureScript and runs in the browser.
3
+ Fluid is a pure functional programming language, with a provenance-tracking runtime and Pythonic syntax. Fluid is implemented in PureScript and runs in the browser.
4
4
 
5
5
  [![develop](https://github.com/explorable-viz/fluid/actions/workflows/develop.yml/badge.svg)](https://github.com/explorable-viz/fluid/actions/workflows/develop.yml)
6
6
  [![GitHub pages](https://github.com/explorable-viz/fluid/actions/workflows/pages/pages-build-deployment/badge.svg)](https://github.com/explorable-viz/fluid/actions/workflows/pages/pages-build-deployment)
7
7
 
8
- ## Installation
8
+ ## End-user setup
9
9
 
10
10
  ### Software required
11
- - git
12
11
  - Node.js >=18.0.0
13
12
  - yarn >= 1.22
14
13
 
15
- Additionally, for Windows users only:
14
+ ### Initial configuration
15
+
16
+ Building a Fluid website usually involves building a Node application:
17
+
18
+ - `yarn add @explorable-viz/fluid`
19
+ - `yarn install` to install Node dependencies
20
+ - `yarn install-website article` to copy example article website from `@exploreable-viz/fluid`
21
+ - Add `dist/` and `website/` folders to `.gitignore`
16
22
 
17
- - [Ubuntu WSL](https://ubuntu.com/desktop/wsl)
23
+ ### Bundling and serving website
24
+ - `yarn bundle-website $WEBSITE_NAME` to bundle website to `dist/$WEBSITE_NAME`
25
+ - `npx http-serve dist/$WEBSITE_NAME -c-1` to serve website at localhost
26
+
27
+ ## Development setup
28
+
29
+ ### Additional software required
30
+ - git
31
+ - (Windows only) [Ubuntu WSL](https://ubuntu.com/desktop/wsl)
18
32
 
19
- ### Building
33
+ ### Initial configuration
20
34
 
21
- - Clone the repository (for Windows users, do this under the Ubuntu WSL)
35
+ - Clone repository (for Windows users, under Ubuntu WSL)
22
36
  - Run `./script/setup/dev-setup.sh` from the top-level directory
23
37
  - `yarn install` to install Node dependencies
24
- - `yarn build`
25
38
 
26
39
  ## Use
27
40
 
28
- The following assumes you have already successfully run `yarn build` (see above).
41
+ - `yarn build` to build interpreter
29
42
 
30
43
  ### Running programs from the command line
31
44
 
@@ -62,8 +62,8 @@ def height(g):
62
62
  h
63
63
 
64
64
  # Float -> Float -> List GraphicsElement -> List GraphicsElement
65
- def spaceRight(z, sep, gs):
66
- zipWith(set_x, iterate(length(gs), (+)(sep), z), gs)
65
+ def space_right(z, sep, gs):
66
+ zip_with(set_x, iterate(length(gs), (+)(sep), z), gs)
67
67
 
68
68
  # Bake colour decisions into the library for the time being. Provide two palettes, so we can have two
69
69
  # different sets of categorical values (e.g. countries and energy types). Palettes from colorbrewer2.org
@@ -94,41 +94,41 @@ def colours2: [
94
94
  # directly because it inherits its frame of reference from its parent. For Viewport, margin will shrink the
95
95
  # available area, possibly to zero, at which point nothing will be rendered.
96
96
  # Float -> GraphicsElement -> GraphicsElement
97
- def scaleToWidth(w, Rect(x, y, _, h, fill)):
97
+ def scale_to_width(w, Rect(x, y, _, h, fill)):
98
98
  Rect(x, y, w, h, fill)
99
- def scaleToWidth(w, Viewport(x, y, w0, h, fill, margin, Scale(x_scale, y_scale), translate, g)):
99
+ def scale_to_width(w, Viewport(x, y, w0, h, fill, margin, Scale(x_scale, y_scale), translate, g)):
100
100
  def scale: Scale((x_scale * w) / w0, y_scale)
101
101
  Viewport(x, y, w, h, fill, margin, scale, translate, g)
102
102
 
103
103
  # Float -> List GraphicsElement -> List GraphicsElement
104
- def stackRight(sep, gs):
105
- map(scaleToWidth(1 - sep), spaceRight(sep / 2, 1, gs))
104
+ def stack_right(sep, gs):
105
+ map(scale_to_width(1 - sep), space_right(sep / 2, 1, gs))
106
106
 
107
107
  # Float -> List GraphicsElement -> GraphicsElement
108
- def groupRight(sep, gs):
109
- Viewport(0, 0, length(gs), maximum(map(height, gs)), "none", 0, Scale(1, 1), Translate(0, 0), Group(stackRight(sep, gs)))
108
+ def group_right(sep, gs):
109
+ Viewport(0, 0, length(gs), maximum(map(height, gs)), "none", 0, Scale(1, 1), Translate(0, 0), Group(stack_right(sep, gs)))
110
110
 
111
111
  # Heuristic saying how often to place a tick on an axis of length n.
112
112
  # Float -> Float
113
- def tickEvery(n):
114
- def m: floor(logBase(10, n))
113
+ def tick_every(n):
114
+ def m: floor(log_base(10, n))
115
115
 
116
116
  if n <= 2 * 10 ** m: 2 * 10 ** (m - 1)
117
117
  else: 10 ** m
118
118
 
119
- def axisStrokeWidth: 0.5
120
- def axisColour: "black"
121
- def backgroundColour: "white"
122
- def defaultMargin: 24
123
- def markerRadius: 3.5
124
- def tickLength: 4
119
+ def axis_stroke_width: 0.5
120
+ def axis_colour: "black"
121
+ def background_colour: "white"
122
+ def default_margin: 24
123
+ def marker_radius: 3.5
124
+ def tick_length: 4
125
125
 
126
126
  # Helpers for axis functions.
127
127
  # Orient -> Colour -> Float -> GraphicsElement
128
128
  def tick(Horiz, colour, len):
129
- Line(Point(0, 0), Point(0, 0 - len), colour, axisStrokeWidth)
129
+ Line(Point(0, 0), Point(0, 0 - len), colour, axis_stroke_width)
130
130
  def tick(Vert, colour, len):
131
- Line(Point(0, 0), Point(0 - len, 0), colour, axisStrokeWidth)
131
+ Line(Point(0, 0), Point(0 - len, 0), colour, axis_stroke_width)
132
132
 
133
133
  # Orient -> Float -> Float -> Str -> GraphicsElement
134
134
  def label(Horiz, x, distance, str):
@@ -137,61 +137,61 @@ def label(Vert, x, distance, str):
137
137
  String(0 - distance, x, str, "end", "central")
138
138
 
139
139
  # Orient -> Colour -> Float -> Str -> GraphicsElement
140
- def labelledTick(orient, colour, len, str):
140
+ def labelled_tick(orient, colour, len, str):
141
141
  Group([
142
142
  tick(orient, colour, len),
143
143
  label(orient, 0, len, str)
144
144
  ])
145
145
 
146
146
  # Orient -> Float -> Float -> Point
147
- def mkPoint(Horiz, x, y): Point(y, x)
148
- def mkPoint(Vert, x, y): Point(x, y)
147
+ def mk_point(Horiz, x, y): Point(y, x)
148
+ def mk_point(Vert, x, y): Point(x, y)
149
149
 
150
150
  # x is position of this axis on the other axis. Returns axis and position of last tick.
151
151
  # Orient -> Float -> Float -> Float -> GraphicsElement
152
152
  def axis(orient, x, start, end):
153
- def tickSp: tickEvery(end - start)
154
- def firstTick: ceilingToNearest(start, tickSp)
155
- def lastTick: ceilingToNearest(end, tickSp)
156
- def n: floor((end - firstTick) / tickSp) + 1
157
- def ys: iterate(n, (+)(tickSp), firstTick)
153
+ def tick_sp: tick_every(end - start)
154
+ def first_tick: ceiling_to_nearest(start, tick_sp)
155
+ def last_tick: ceiling_to_nearest(end, tick_sp)
156
+ def n: floor((end - first_tick) / tick_sp) + 1
157
+ def ys: iterate(n, (+)(tick_sp), first_tick)
158
158
  def ys:
159
- if firstTick > start: start :| ys
159
+ if first_tick > start: start :| ys
160
160
  else: ys
161
161
  def ys:
162
- if lastTick > end: concat2(ys, [lastTick])
162
+ if last_tick > end: concat2(ys, [last_tick])
163
163
  else: ys
164
- def ps: map(mkPoint(orient, x), ys)
164
+ def ps: map(mk_point(orient, x), ys)
165
165
  def ax:
166
166
  Group([
167
- Line(head(ps), last(ps), axisColour, axisStrokeWidth),
168
- Polymarkers(ps, flip(map, ys, compose(labelledTick(orient, axisColour, tickLength), numToStr)))
167
+ Line(head(ps), last(ps), axis_colour, axis_stroke_width),
168
+ Polymarkers(ps, flip(map, ys, compose(labelled_tick(orient, axis_colour, tick_length), num_to_str)))
169
169
  ])
170
170
 
171
- (ax, lastTick)
171
+ (ax, last_tick)
172
172
 
173
173
  # x is position of this axis on the other axis.
174
174
  # Orient -> Float -> List Cat -> GraphicsElement
175
- def catAxis(orient, x, catValues):
176
- def ys: iterate(length(catValues) + 1, (+)(1), 0)
177
- def ps: map(mkPoint(orient, x), ys)
175
+ def cat_axis(orient, x, cat_values):
176
+ def ys: iterate(length(cat_values) + 1, (+)(1), 0)
177
+ def ps: map(mk_point(orient, x), ys)
178
178
 
179
179
  Group([
180
- Line(head(ps), last(ps), axisColour, axisStrokeWidth),
181
- Polymarkers(tail(ps), map(const(tick(orient, axisColour, tickLength)), catValues)),
182
- Polymarkers(flip(map, tail(ps), lambda Point(x, y): Point(x - 0.5, y)), map(label(orient, -0.5, 0), catValues))
180
+ Line(head(ps), last(ps), axis_colour, axis_stroke_width),
181
+ Polymarkers(tail(ps), map(const(tick(orient, axis_colour, tick_length)), cat_values)),
182
+ Polymarkers(flip(map, tail(ps), lambda Point(x, y): Point(x - 0.5, y)), map(label(orient, -0.5, 0), cat_values))
183
183
  ])
184
184
 
185
185
  # Float -> Float -> Float -> Float -> List GraphicsElement -> GraphicsElement
186
186
  def viewport(x_start, x_finish, y_finish, margin, gs):
187
- Viewport(0, 0, x_finish - x_start, y_finish, backgroundColour, margin, Scale(1, 1), Translate(0 - x_start, 0), Group(gs))
187
+ Viewport(0, 0, x_finish - x_start, y_finish, background_colour, margin, Scale(1, 1), Translate(0 - x_start, 0), Group(gs))
188
188
 
189
189
  # Plot a map of x values to lists of (categorical value, y value) pairs. Importantly, assume all data is uniform
190
190
  # (categorical keys are the same for each x value and are ordered the same each time).
191
191
  # Bool -> Colours -> Float -> List (Float, List (Cat, Float)) -> GraphicsElement
192
- def lineChart(withAxes, colours, x_start, data):
192
+ def line_chart(with_axes, colours, x_start, data):
193
193
  def xs: map(fst, data)
194
- def nCat: length(snd(head(data)))
194
+ def n_cat: length(snd(head(data)))
195
195
 
196
196
  # (Int, Colour) -> GraphicsElement
197
197
  def plot((n, colour)):
@@ -200,46 +200,46 @@ def lineChart(withAxes, colours, x_start, data):
200
200
 
201
201
  Group([
202
202
  Polyline(ps, colour, 1),
203
- Polymarkers(ps, repeat(length(ps), Circle(0, 0, markerRadius, colour)))
203
+ Polymarkers(ps, repeat(length(ps), Circle(0, 0, marker_radius, colour)))
204
204
  ])
205
205
 
206
206
  # List GraphicsElement
207
207
  def lines:
208
- zipWith(curry(plot), iterate(nCat, (+)(1), 0), colours)
208
+ zip_with(curry(plot), iterate(n_cat, (+)(1), 0), colours)
209
209
  def x_finish: last(xs)
210
210
  def y_finish:
211
211
  maximum(flip(map, data, lambda (_, kvs): maximum(map(snd, kvs))))
212
212
 
213
- if withAxes:
213
+ if with_axes:
214
214
  def (x_axis, x_finish): axis(Horiz, 0, x_start, x_finish)
215
215
  def (y_axis, y_finish_): axis(Vert, x_start, 0, y_finish)
216
- viewport(x_start, x_finish, y_finish_, defaultMargin, x_axis :| y_axis :| lines)
216
+ viewport(x_start, x_finish, y_finish_, default_margin, x_axis :| y_axis :| lines)
217
217
  else:
218
218
  viewport(x_start, x_finish, y_finish, 0, lines)
219
219
 
220
220
  # Plot a chart of categorical values on the x-axis and renderings of the corresponding a-value on the y-axis.
221
221
  # (Colours -> List a -> GraphicsElement) -> Bool -> Colours -> Float -> List (Cat, a) -> GraphicsElement
222
- def categoricalChart(plotValue, withAxes, colours, sep, data):
222
+ def categorical_chart(plot_value, with_axes, colours, sep, data):
223
223
  def gs:
224
- stackRight(sep, plotValue(colours, map(snd, data)))
224
+ stack_right(sep, plot_value(colours, map(snd, data)))
225
225
  def w: length(gs)
226
226
  def h: maximum(map(height, gs))
227
227
 
228
- if withAxes:
229
- def x_axis: catAxis(Horiz, 0, map(fst, data))
228
+ if with_axes:
229
+ def x_axis: cat_axis(Horiz, 0, map(fst, data))
230
230
  def (y_axis, h_): axis(Vert, 0, 0, h)
231
- viewport(0, w, h_, defaultMargin, concat2(gs, [x_axis, y_axis]))
231
+ viewport(0, w, h_, default_margin, concat2(gs, [x_axis, y_axis]))
232
232
  else:
233
233
  viewport(0, w, h, 0, gs)
234
234
 
235
235
  # Colours -> List a -> GraphicsElement
236
236
  def rects(colours, ns):
237
- zipWith(lambda colour, n: Rect(0, 0, 1, n, colour), colours, ns)
237
+ zip_with(lambda colour, n: Rect(0, 0, 1, n, colour), colours, ns)
238
238
 
239
239
  # First component of data (categorical value) currently ignored; values just mapped positionally to colors.
240
240
  # Can we use Group instead of Viewport here?
241
241
  # Colours -> List (a, Num) -> GraphicsElement
242
- def stackedBar(colours, ns):
242
+ def stacked_bar(colours, ns):
243
243
  def heights: map(snd, ns)
244
244
  def subtotals: scanl1((+), 0, heights)
245
245
  def dims: zip(0 :| subtotals, heights)
@@ -249,18 +249,18 @@ def stackedBar(colours, ns):
249
249
  Viewport(0, 0, 1, last(subtotals), "none", 0, Scale(1, 1), Translate(0, 0), Group(rects))
250
250
 
251
251
  # Bool -> Colours -> Float -> List (a, Float) -> GraphicsElement
252
- def barChart:
253
- categoricalChart(rects)
252
+ def bar_chart:
253
+ categorical_chart(rects)
254
254
 
255
255
  # For each categorical value of type a, plot a bar chart for the corresponding b-indexed data.
256
256
  # Bool -> Colours -> Float -> List (a, List (b, Float)) -> GraphicsElement
257
- def groupedBarChart:
258
- categoricalChart(compose(map, flip(barChart(False), 0)))
257
+ def grouped_bar_chart:
258
+ categorical_chart(compose(map, flip(bar_chart(False), 0)))
259
259
 
260
- # See stackedBar for strong (unjustified) assumption about uniformity of data.
260
+ # See stacked_bar for strong (unjustified) assumption about uniformity of data.
261
261
  # Bool -> Colours -> Num -> List (a, List (b, Num)) -> GraphicsElement
262
- def stackedBarChart:
263
- categoricalChart(compose(map, stackedBar))
262
+ def stacked_bar_chart:
263
+ categorical_chart(compose(map, stacked_bar))
264
264
 
265
265
  # Bit of a hack, but how text fits into our model is a bit unclear at the moment.
266
266
  # Str -> GraphicsElement -> GraphicsElement
@@ -271,4 +271,4 @@ def caption(str, Viewport(x, y, w, h, fill, margin, scale, translate, g)):
271
271
  Viewport(0, 0, w, h, fill, margin, scale, translate, g)
272
272
  ])
273
273
 
274
- Viewport(x, y, w, h, backgroundColour, defaultMargin / 2 + 4, Scale(1, 1), Translate(0, 0), g_)
274
+ Viewport(x, y, w, h, background_colour, default_margin / 2 + 4, Scale(1, 1), Translate(0, 0), g_)
@@ -1,23 +1,23 @@
1
1
  def zero(m, n, image):
2
- def (m_max, n_max): dims(image)
3
- if m >= 1 |and| m <= m_max |and| n >= 1 |and| n <= n_max: image ! (m, n)
2
+ def (m_size, n_size): dims(image)
3
+ if m >= 0 and m < m_size and n >= 0 and n < n_size: image ! (m, n)
4
4
  else: 0
5
5
 
6
6
  def wrap(m, n, image):
7
- def (m_max, n_max): dims(image)
8
- image ! (((m - 1) |mod| m_max) + 1, ((n - 1) |mod| n_max) + 1)
7
+ def (m_size, n_size): dims(image)
8
+ image ! (m % m_size, n % n_size)
9
9
 
10
10
  def extend(m, n, image):
11
- def (m_max, n_max): dims(image)
12
- def m':
13
- min(max(m, 1), m_max)
14
- def n':
15
- min(max(n, 1), n_max)
16
- image ! (m', n')
11
+ def (m_size, n_size): dims(image)
12
+ def m_:
13
+ min(max(m, 0), m_size - 1)
14
+ def n_:
15
+ min(max(n, 0), n_size - 1)
16
+ image ! (m_, n_)
17
17
 
18
- def matrixSum(matr):
18
+ def matrix_sum(matr):
19
19
  def (m, n): dims(matr)
20
- foldl((+), 0, [matr ! (i, j) for (i, j) in range((1, 1), (m, n))])
20
+ foldl((+), 0, [matr ! (i, j) for (i, j) in range2d((0, 0), (m, n))])
21
21
 
22
22
  def convolve(image, kernel, lookup):
23
23
  def ((m, n), (i, j)):
@@ -25,16 +25,16 @@ def convolve(image, kernel, lookup):
25
25
  def (half_i, half_j):
26
26
  (i |quot| 2, j |quot| 2)
27
27
  def area: i * j
28
- def interMatrix(m', n'):
29
- [| lookup(((m' + i') - 1) - half_i, ((n' + j') - 1) - half_j, image) * kernel ! (i', j') for (i', j') in (i, j) |]
28
+ def interMatrix(m_, n_):
29
+ [| lookup(m_ + i_ - half_i, n_ + j_ - half_j, image) * kernel ! (i_, j_) for (i_, j_) in (i, j) |]
30
30
 
31
- [| matrixSum(interMatrix(m', n')) |quot| area for (m', n') in (m, n) |]
31
+ [| matrix_sum(interMatrix(m_, n_)) |quot| area for (m_, n_) in (m, n) |]
32
32
 
33
- def matMul(a, b):
33
+ def mat_mul(a, b):
34
34
  def ((m, n), (i, j)): (dims(a), dims(b))
35
35
 
36
36
  if not(n == i):
37
37
  error("Dimensions don't line up")
38
38
  else:
39
39
  @doc(f"""Intermediate matrix""")
40
- [| sum([a!(i_, k) * b!(k, j_) for k in enumFromTo(1, n)]) for (i_, j_) in (m, j) |]
40
+ [| sum([a!(i_, k) * b!(k, j_) for k in range(0, n)]) for (i_, j_) in (m, j) |]
@@ -23,18 +23,18 @@ def compare(x, y):
23
23
  else: EQ
24
24
 
25
25
  # (b -> b -> c) -> (a -> b) -> a -> a -> c
26
- def on(binOp, prop, x, y):
27
- binOp(prop(x), prop(y))
26
+ def on(bin_op, prop, x, y):
27
+ bin_op(prop(x), prop(y))
28
28
 
29
29
  # Num -> Num
30
30
  def negate: (-)(0)
31
31
 
32
32
  # Log of x in base y.
33
33
  # Float -> Float -> Float
34
- def logBase(x, y): log(y) / log(x)
34
+ def log_base(x, y): log(y) / log(x)
35
35
 
36
36
  # Float -> Float -> Float
37
- def ceilingToNearest(n, m): ceiling(n / m) * m
37
+ def ceiling_to_nearest(n, m): ceiling(n / m) * m
38
38
 
39
39
  # (b -> c) -> (a -> b) -> a -> c
40
40
  # Want infix <<<
@@ -87,7 +87,7 @@ def tail(_ :| xs): xs
87
87
  # Eq a => a -> List a -> Bool
88
88
  def elem(x, []): False
89
89
  def elem(x, y :| xs):
90
- x == y |or| elem(x, xs)
90
+ x == y or elem(x, xs)
91
91
 
92
92
  # (a -> Bool) -> List a -> Option a
93
93
  def find(p, []): None
@@ -96,16 +96,16 @@ def find(p, x :| xs):
96
96
  else: find(p, xs)
97
97
 
98
98
  # String -> String -> List Dict -> Option Dict
99
- def findWithKey(k, v, rs):
99
+ def find_with_key(k, v, rs):
100
100
  find(lambda y: y[k] == v, rs)
101
101
 
102
102
  # Option a -> a
103
- def fromSome(None): error("Expected Some!")
104
- def fromSome(Some(x)): x
103
+ def from_some(None): error("Expected Some!")
104
+ def from_some(Some(x)): x
105
105
 
106
106
  # Option a -> a -> a
107
- def fromOption(None, y): y
108
- def fromOption(Some(x), _): x
107
+ def from_option(None, y): y
108
+ def from_option(Some(x), _): x
109
109
 
110
110
  # (a -> Bool) -> List a -> List a
111
111
  def filter(p, []): []
@@ -116,12 +116,12 @@ def filter(p, x :| xs):
116
116
  else: ys
117
117
 
118
118
  # (a -> Option b) -> List a -> List b
119
- def filterMap(p, []): []
120
- def filterMap(p, x :| xs):
119
+ def filter_map(p, []): []
120
+ def filter_map(p, x :| xs):
121
121
  match p(x):
122
- case None: filterMap(f, xs)
122
+ case None: filter_map(f, xs)
123
123
  case Some(y):
124
- y :| filterMap(f, xs)
124
+ y :| filter_map(f, xs)
125
125
 
126
126
  # Equivalent to but more efficient than length ∘ filter(p)
127
127
  def count_if(p):
@@ -142,10 +142,10 @@ def span(p, x :| xs_):
142
142
 
143
143
  # Each returned list is non-empty.
144
144
  # (a -> a -> Bool) -> List a -> List (List a)
145
- def groupBy(eq, Nil): Nil
146
- def groupBy(eq, x :| xs):
145
+ def group_by(eq, Nil): Nil
146
+ def group_by(eq, x :| xs):
147
147
  def { init: ys, rest: zs }: span(eq(x), xs)
148
- (x :| ys) :| groupBy(eq, zs)
148
+ (x :| ys) :| group_by(eq, zs)
149
149
 
150
150
  # (a -> b -> a) -> a -> List b -> a
151
151
  def foldl(op, z, []): z
@@ -192,10 +192,13 @@ def concat2(x :| xs, ys):
192
192
  x :| concat2(xs, ys)
193
193
 
194
194
  # List (List a) -> List a
195
- def concat: foldl(concat2, [])
195
+ def concat: foldr(concat2, [])
196
196
 
197
197
  # (a -> List b) -> List a -> List b
198
- def concatMap(f, xs): concat(map(f, xs))
198
+ def concat_map(f, xs): concat(map(f, xs))
199
+
200
+ # List String -> String
201
+ def join: foldr((++), "")
199
202
 
200
203
  # List a -> a -> List a
201
204
  def intersperse([], _): []
@@ -210,7 +213,7 @@ def iterate(n, f, z):
210
213
  z :| map(f, iterate(n - 1, f, z))
211
214
 
212
215
  # List Num -> Num
213
- def sum: foldl((+), 0)
216
+ def sum: foldr((+), 0)
214
217
 
215
218
  # List Num -> Num
216
219
  def mean(xs):
@@ -251,7 +254,7 @@ def drop(n, xs):
251
254
  case _ :| xs: drop(n - 1, xs)
252
255
 
253
256
  # Int -> List a -> List a
254
- def lastN(n, xs):
257
+ def last_n(n, xs):
255
258
  foldl(compose(const, drop(1)), xs, drop(n, xs))
256
259
 
257
260
  # Expects non-negative integer as first argument and non-empty list as second argument.
@@ -260,9 +263,9 @@ def nth(n, x :| xs):
260
263
  if n == 0: x
261
264
  else: nth(n - 1, xs)
262
265
 
263
- # Matrix Int -> Int -> Int -> Int
266
+ # Int -> Int -> List (List Int) -> Int
264
267
  def nth2(i, j, xss):
265
- nth(j - 1, nth(i - 1, xss))
268
+ nth(j, nth(i, xss))
266
269
 
267
270
  # Partial; requires k to be in the map.
268
271
  # Int -> List (Int, b) -> b
@@ -295,24 +298,22 @@ def unzip((x, y) :| zs):
295
298
  (x :| xs, y :| ys)
296
299
 
297
300
  # (a -> b -> c) -> List a -> List b -> List c
298
- def zipWith(op, [], ys): []
299
- def zipWith(op, x :| xs, []): []
300
- def zipWith(op, x :| xs, y :| ys):
301
- op(x, y) :| zipWith(op, xs, ys)
301
+ def zip_with(op, [], ys): []
302
+ def zip_with(op, x :| xs, []): []
303
+ def zip_with(op, x :| xs, y :| ys):
304
+ op(x, y) :| zip_with(op, xs, ys)
302
305
 
303
306
  # List a -> List b -> List (a, b)
304
- def zip: zipWith(curry(id))
307
+ def zip: zip_with(curry(id))
305
308
 
306
- # Rename to 'range'
307
309
  # Int -> Int -> List Int
308
- def enumFromTo(n, m):
309
- if n <= m: n :| [n + 1 .. m]
310
+ def range(n, m):
311
+ if n < m: n :| range(n + 1, m)
310
312
  else: []
311
313
 
312
- # Rename to 'range2'
313
314
  # (Int, Int) -> (Int, Int) -> List (Int, Int)
314
- def range((m1, n1), (m2, n2)):
315
- [(i1, i2) for i1 in [m1 .. m2] for i2 in [n1 .. n2]]
315
+ def range2d((m1, n1), (m2, n2)):
316
+ [(i1, i2) for i1 in range(m1, m2) for i2 in range(n1, n2)]
316
317
 
317
318
  # Int -> Int -> Int
318
319
  def abs(x, y):
@@ -335,7 +336,7 @@ def slice(begin, end, xs):
335
336
  take(end - begin, drop(begin, xs))
336
337
 
337
338
  # (a -> Boolean) -> List a -> (List a, List a)
338
- def splitOn(p, data):
339
+ def split_on(p, data):
339
340
  def go(fls, trs, []):
340
341
  (reverse(fls), reverse(trs))
341
342
  def go(fls, trs, x :| xs):
@@ -17,7 +17,7 @@ def mergesort(xs):
17
17
  def (ys, zs): split(xs)
18
18
  merge(mergesort(ys), mergesort(zs))
19
19
 
20
- def findQuantile(q, p, xs):
20
+ def find_quantile(q, p, xs):
21
21
  def rank:
22
22
  (p / q) * (length(xs) - 1)
23
23
 
@@ -30,49 +30,49 @@ def findQuantile(q, p, xs):
30
30
  def right: nth(x2, xs)
31
31
  left + (rank - x1) * (right - left)
32
32
 
33
- def findPercentile: findQuantile(100)
33
+ def find_percentile: find_quantile(100)
34
34
 
35
- def accumBins(data, Nil): []
36
- def accumBins(data, [l]): []
37
- def accumBins(data, l :| r :| es):
35
+ def accum_bins(data, Nil): []
36
+ def accum_bins(data, [l]): []
37
+ def accum_bins(data, l :| r :| es):
38
38
  def (ge, le):
39
- splitOn(lambda x: x <= r, data)
40
- (le, r - l) :| accumBins(ge, r :| es)
39
+ split_on(lambda x: x <= r, data)
40
+ (le, r - l) :| accum_bins(ge, r :| es)
41
41
 
42
42
  def cut(xs, nbins):
43
43
  def low: minimum(xs)
44
44
  def binwidth:
45
45
  (maximum(xs) - low) / nbins
46
46
  def edges:
47
- [low + x * binwidth for x in enumFromTo(0, nbins)]
47
+ [low + x * binwidth for x in [0 .. nbins]]
48
48
 
49
- accumBins(xs, edges)
49
+ accum_bins(xs, edges)
50
50
 
51
51
  def qcut(xs, qs):
52
52
  def (low, high):
53
53
  (minimum(xs), maximum(xs))
54
54
  def edges:
55
- append((low :| [findPercentile(x, xs) for x in qs], [high]))
55
+ append((low :| [find_percentile(x, xs) for x in qs], [high]))
56
56
 
57
- accumBins(xs, edges)
57
+ accum_bins(xs, edges)
58
58
 
59
- def likelihoodLE(xs, target):
59
+ def likelihood_le(xs, target):
60
60
  length(filter(lambda x: x <= target, xs)) / length(xs)
61
61
 
62
- def likelihoodGE(xs, target):
62
+ def likelihood_ge(xs, target):
63
63
  length(filter(lambda x: x >= target, xs)) / length(xs)
64
64
 
65
- def likelihoodMap(table, prob):
66
- fromSome(find(lambda x: x.prob <= prob, table)).msg
65
+ def likelihood_map(table, prob):
66
+ from_some(find(lambda x: x.prob <= prob, table)).msg
67
67
 
68
- def mkPercent(num):
69
- numToStr(num * 100) ++ "%"
68
+ def mk_percent(num):
69
+ num_to_str(num * 100) ++ "%"
70
70
 
71
- def leqP(n, m):
71
+ def leq_p(n, m):
72
72
  if n <= m: "less"
73
73
  else: "more"
74
74
 
75
- def gradedLeqP(n, m):
75
+ def graded_leq_p(n, m):
76
76
  def ratio: n / m
77
77
 
78
78
  if ratio <= 1.0: