fusion-lang 0.0.1 → 0.0.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.
- checksums.yaml +4 -4
- data/.mutant.yml +24 -0
- data/.simplecov +11 -0
- data/CHANGELOG.md +42 -0
- data/README.md +2 -1
- data/Rakefile +8 -0
- data/docs/lang/design.md +54 -5
- data/docs/lang/implementation.md +41 -0
- data/docs/user/how-to-guides.md +90 -5
- data/docs/user/reference.md +48 -37
- data/docs/user/tutorial.md +6 -5
- data/examples/double.fsn +4 -1
- data/examples/factorial.fsn +6 -3
- data/examples/gcd.fsn +9 -0
- data/examples/matrix/OP.fsn +2 -0
- data/examples/matrix/average.fsn +2 -0
- data/examples/matrix/solve.fsn +2 -0
- data/exe/fusion +2 -2
- data/lib/fusion/ast.rb +76 -28
- data/lib/fusion/atom.rb +1 -1
- data/lib/fusion/cli/decoder.rb +6 -6
- data/lib/fusion/cli/encoder.rb +2 -2
- data/lib/fusion/cli/options.rb +11 -8
- data/lib/fusion/cli/parser.rb +1 -1
- data/lib/fusion/cli/repl.rb +6 -6
- data/lib/fusion/cli/serializer.rb +6 -7
- data/lib/fusion/cli.rb +1 -1
- data/lib/fusion/interpreter/builtins.rb +51 -22
- data/lib/fusion/interpreter/thunk.rb +2 -2
- data/lib/fusion/interpreter.rb +31 -23
- data/lib/fusion/lexer.rb +62 -40
- data/lib/fusion/parser.rb +72 -35
- data/lib/fusion/version.rb +3 -1
- data/lib/fusion.rb +0 -1
- data/stdlib/all.fsn +2 -2
- data/stdlib/any.fsn +3 -3
- data/stdlib/compact.fsn +2 -3
- data/stdlib/concat.fsn +4 -3
- data/stdlib/entries.fsn +6 -0
- data/stdlib/filter.fsn +3 -3
- data/stdlib/map.fsn +3 -2
- data/stdlib/matrix/Matrix.fsn +8 -0
- data/stdlib/matrix/OP.fsn +18 -0
- data/stdlib/matrix/add.fsn +7 -0
- data/stdlib/matrix/column.fsn +6 -0
- data/stdlib/matrix/determinant.fsn +16 -0
- data/stdlib/matrix/dimensions.fsn +5 -0
- data/stdlib/matrix/identity.fsn +6 -0
- data/stdlib/matrix/invert.fsn +26 -0
- data/stdlib/matrix/minor.fsn +15 -0
- data/stdlib/matrix/multiply.fsn +10 -0
- data/stdlib/matrix/negate.fsn +5 -0
- data/stdlib/matrix/product.fsn +11 -0
- data/stdlib/matrix/rotate.fsn +10 -0
- data/stdlib/matrix/row.fsn +6 -0
- data/stdlib/matrix/scale.fsn +6 -0
- data/stdlib/matrix/subtract.fsn +7 -0
- data/stdlib/matrix/sum.fsn +14 -0
- data/stdlib/matrix/transpose.fsn +5 -0
- data/stdlib/range.fsn +2 -2
- data/stdlib/safe.fsn +7 -0
- data/stdlib/sanitize.fsn +2 -3
- data/stdlib/toObject.fsn +7 -0
- data/stdlib/vector/Vector.fsn +7 -0
- data/stdlib/vector/add.fsn +6 -0
- data/stdlib/vector/cross.fsn +6 -0
- data/stdlib/vector/dot.fsn +6 -0
- data/stdlib/vector/norm.fsn +6 -0
- data/stdlib/vector/scale.fsn +5 -0
- data/stdlib/vector/subtract.fsn +6 -0
- data/stdlib/zip.fsn +6 -0
- metadata +37 -5
- data/stdlib/gt.fsn +0 -9
- data/stdlib/gte.fsn +0 -9
- data/stdlib/lt.fsn +0 -9
- data/stdlib/lte.fsn +0 -9
data/stdlib/entries.fsn
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
# Destructure an object into an array of its [key, value] entries, in insertion
|
|
2
|
+
# order. The inverse of @toObject.
|
|
3
|
+
(
|
|
4
|
+
obj ? @Object => obj | @keys |: (k => [k, obj[k]]),
|
|
5
|
+
x => !{"kind": "argument_error", "origin": "stdlib", "operation": "@entries", "status": 0, "input": x, "expected": ["_ ? @Object"]}
|
|
6
|
+
)
|
data/stdlib/filter.fsn
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
_ ? @falsey => {"f": f, "c": rest} | @,
|
|
7
7
|
_ => [x, ...({"f": f, "c": rest} | @)],
|
|
8
8
|
),
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
x => !{"kind": "argument_error", "origin": "stdlib", "operation": "@filter", "status": 0, "input": x, "expected": ["{\"f\": _ ? @Function, \"c\": _ ? @
|
|
9
|
+
# Reduce to array case
|
|
10
|
+
{"f": f ? @Function, "c": obj ? @Object} => {"f": ([_, v] => v | f), "c": obj | @entries} | @ | @toObject,
|
|
11
|
+
x => !{"kind": "argument_error", "origin": "stdlib", "operation": "@filter", "status": 0, "input": x, "expected": ["{\"f\": _ ? @Function, \"c\": _ ? @Collection}"]}
|
|
12
12
|
)
|
data/stdlib/map.fsn
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
(
|
|
4
4
|
{"f": _ ? @Function, "c": []} => [],
|
|
5
5
|
{"f": f ? @Function, "c": [x, ...rest]} => [x | f, ...({"f": f, "c": rest} | @)],
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
# Reduce to array case
|
|
7
|
+
{"f": f ? @Function, "c": obj ? @Object} => {"f": ([k, v] => [k, v | f]), "c": obj | @entries} | @ | @toObject,
|
|
8
|
+
x => !{"kind": "argument_error", "origin": "stdlib", "operation": "@map", "status": 0, "input": x, "expected": ["{\"f\": _ ? @Function, \"c\": _ ? @Collection}"]}
|
|
8
9
|
)
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# True for a matrix: a non-empty array of equally sized vectors (@vector/Vector).
|
|
2
|
+
# A predicate: false for anything else, never an error.
|
|
3
|
+
(rows => [
|
|
4
|
+
rows | @Array,
|
|
5
|
+
rows | @size > 0,
|
|
6
|
+
{"c": rows, "f": @vector/Vector} | @all,
|
|
7
|
+
rows |: @size | @OP.equal,
|
|
8
|
+
] | @OP.and | @safe)
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# The operators reskinned for matrices. Point a directory's OP.fsn at
|
|
2
|
+
# `@matrix/OP` to make the arithmetic sugar operate on matrices: `a + b`
|
|
3
|
+
# (elementwise sum), `-a` / `a - b` (elementwise negation), `a * b` (matrix
|
|
4
|
+
# product), `/a` (inverse), `a / b` (multiply by the inverse). `//` and `%`
|
|
5
|
+
# have no matrix meaning and always raise. The spread keeps every other member
|
|
6
|
+
# (equal, compare and its readers, the boolean operators) at its builtin
|
|
7
|
+
# meaning — this module's own files rely on that: they use the comparison and
|
|
8
|
+
# boolean sugar and plain `@OP` references freely, and reserve `@@OP` for the
|
|
9
|
+
# scalar versions of the arithmetic members this file overrides.
|
|
10
|
+
{
|
|
11
|
+
...@@,
|
|
12
|
+
"sum": @sum,
|
|
13
|
+
"negate": @negate,
|
|
14
|
+
"product": @product,
|
|
15
|
+
"invert": @invert,
|
|
16
|
+
"quotient": (x => !{"kind": "math_error", "origin": "stdlib", "operation": "@matrix/OP.quotient", "status": 0, "input": x, "message": "integer division is not defined for matrices"}),
|
|
17
|
+
"modulo": (x => !{"kind": "math_error", "origin": "stdlib", "operation": "@matrix/OP.modulo", "status": 0, "input": x, "message": "modulo is not defined for matrices"}),
|
|
18
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# Add two equally sized matrices elementwise: zip the rows and add each pair
|
|
2
|
+
# through @vector/add. Input: [a, b].
|
|
3
|
+
(
|
|
4
|
+
[a, b] ? ([x ? @Matrix, y ? @Matrix] => [x, y] |: @dimensions | @OP.equal) =>
|
|
5
|
+
[a, b] | @zip |: @vector/add,
|
|
6
|
+
x => !{"kind": "argument_error", "origin": "stdlib", "operation": "@matrix/add", "status": 0, "input": x, "expected": ["_ ? ([a ? @matrix/Matrix, b ? @matrix/Matrix] => [a, b] |: @matrix/dimensions | @OP.equal)"]}
|
|
7
|
+
)
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
# Extract the i-th (0-based) column of a matrix as a vector. Input: [matrix, index].
|
|
2
|
+
(
|
|
3
|
+
[m, i] ? ([x ? @Matrix, n ? @Integer] => n >= 0 && n < (x | @dimensions).columns) =>
|
|
4
|
+
m |: (row => row[i]),
|
|
5
|
+
x => !{"kind": "argument_error", "origin": "stdlib", "operation": "@matrix/column", "status": 0, "input": x, "expected": ["_ ? ([m ? @matrix/Matrix, i ? @Integer] => i >= 0 && i < (m | @matrix/dimensions).columns)"]}
|
|
6
|
+
)
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Determinant of a square matrix, by Laplace expansion along the first row: the
|
|
2
|
+
# dot product of the first row with its cofactors (signed minor determinants).
|
|
3
|
+
(
|
|
4
|
+
m ? (sq ? @Matrix => sq | @dimensions | (d => d.rows == d.columns)) =>
|
|
5
|
+
m | (
|
|
6
|
+
[[a]] => a,
|
|
7
|
+
[firstRow, ...] =>
|
|
8
|
+
[
|
|
9
|
+
firstRow,
|
|
10
|
+
(m | @dimensions).columns | @range |: (j =>
|
|
11
|
+
[[-1, j] | @math.pow, [m, 0, j] | @minor | @] | @@OP.product
|
|
12
|
+
),
|
|
13
|
+
] | @vector/dot
|
|
14
|
+
),
|
|
15
|
+
x => !{"kind": "argument_error", "origin": "stdlib", "operation": "@matrix/determinant", "status": 0, "input": x, "expected": ["_ ? (sq ? @matrix/Matrix => sq | @matrix/dimensions | (d => d.rows == d.columns))"]}
|
|
16
|
+
)
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
# The dimensions of a matrix, as {"rows": _, "columns": _}.
|
|
2
|
+
(
|
|
3
|
+
m ? @Matrix => {"rows": m | @size, "columns": m[0] | @size},
|
|
4
|
+
x => !{"kind": "argument_error", "origin": "stdlib", "operation": "@matrix/dimensions", "status": 0, "input": x, "expected": ["_ ? @matrix/Matrix"]}
|
|
5
|
+
)
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
# The n-by-n identity matrix for a positive integer n.
|
|
2
|
+
(
|
|
3
|
+
n ? (i ? @Integer => i > 0) =>
|
|
4
|
+
n | @range |: (r => n | @range |: (c => (r == c) | (true => 1, false => 0))),
|
|
5
|
+
x => !{"kind": "argument_error", "origin": "stdlib", "operation": "@matrix/identity", "status": 0, "input": x, "expected": ["_ ? (n ? @Integer => n > 0)"]}
|
|
6
|
+
)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Inverse of a square matrix with a non-zero determinant: the adjugate scaled
|
|
2
|
+
# by 1/determinant. Adjugate entry (i, j) is (-1)^(i+j) * determinant(minor(j, i)).
|
|
3
|
+
(
|
|
4
|
+
m ? (sq ? @Matrix => sq | @dimensions | (d => d.rows == d.columns)) =>
|
|
5
|
+
m | @determinant | (det => (det ?? 0) | (
|
|
6
|
+
0 => !{"kind": "math_error", "origin": "stdlib", "operation": "@matrix/invert", "status": 0, "input": m, "message": "singular matrix (determinant 0)"},
|
|
7
|
+
_ => m | (
|
|
8
|
+
[[a]] => [[a | @@OP.invert]],
|
|
9
|
+
_ =>
|
|
10
|
+
[
|
|
11
|
+
det | @@OP.invert,
|
|
12
|
+
m | @dimensions | (d =>
|
|
13
|
+
d.rows | @range |: (i =>
|
|
14
|
+
d.columns | @range |: (j =>
|
|
15
|
+
[
|
|
16
|
+
[-1, [i, j] | @@OP.sum] | @math.pow,
|
|
17
|
+
[m, j, i] | @minor | @determinant,
|
|
18
|
+
] | @@OP.product
|
|
19
|
+
)
|
|
20
|
+
)
|
|
21
|
+
),
|
|
22
|
+
] | @scale
|
|
23
|
+
)
|
|
24
|
+
)),
|
|
25
|
+
x => !{"kind": "argument_error", "origin": "stdlib", "operation": "@matrix/invert", "status": 0, "input": x, "expected": ["_ ? (sq ? @matrix/Matrix => sq | @matrix/dimensions | (d => d.rows == d.columns))"]}
|
|
26
|
+
)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# The minor of a matrix: drop row r and column c. Input: [matrix, r, c]. The
|
|
2
|
+
# matrix must be at least 2 by 2, so the minor is a matrix again.
|
|
3
|
+
(
|
|
4
|
+
[m, r, c] ? ([x ? @Matrix, row ? @Integer, col ? @Integer] =>
|
|
5
|
+
x | @dimensions | (d =>
|
|
6
|
+
row >= 0 && row < d.rows &&
|
|
7
|
+
col >= 0 && col < d.columns &&
|
|
8
|
+
d.rows >= 2 && d.columns >= 2)) =>
|
|
9
|
+
m | @dimensions | (d =>
|
|
10
|
+
d.rows | @range |? (k => ~(k == r)) |: (k =>
|
|
11
|
+
d.columns | @range |? (l => ~(l == c)) |: (l => m[k][l])
|
|
12
|
+
)
|
|
13
|
+
),
|
|
14
|
+
x => !{"kind": "argument_error", "origin": "stdlib", "operation": "@matrix/minor", "status": 0, "input": x, "expected": ["_ ? ([m ? @matrix/Matrix, r ? @Integer, c ? @Integer] => m | @matrix/dimensions | (d => r >= 0 && r < d.rows && c >= 0 && c < d.columns && d.rows >= 2 && d.columns >= 2))"]}
|
|
15
|
+
)
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Matrix multiplication of a pair [a, b]: a's column count must equal b's row
|
|
2
|
+
# count. Entry (i, j) is the dot product of a's row i and b's column j — the
|
|
3
|
+
# columns are the rows of the transposed b, computed once.
|
|
4
|
+
(
|
|
5
|
+
[a, b] ? ([x ? @Matrix, y ? @Matrix] => (x | @dimensions).columns == (y | @dimensions).rows) =>
|
|
6
|
+
b | @transpose | (columns =>
|
|
7
|
+
a |: (row => columns |: (column => [row, column] | @vector/dot))
|
|
8
|
+
),
|
|
9
|
+
x => !{"kind": "argument_error", "origin": "stdlib", "operation": "@matrix/multiply", "status": 0, "input": x, "expected": ["_ ? ([x ? @matrix/Matrix, y ? @matrix/Matrix] => (x | @matrix/dimensions).columns == (y | @matrix/dimensions).rows)"]}
|
|
10
|
+
)
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Product of a non-empty array of matrices, folded left through
|
|
2
|
+
# @matrix/multiply. A dimension mismatch surfaces as @matrix/multiply's error.
|
|
3
|
+
(
|
|
4
|
+
matrices ? (ms => [
|
|
5
|
+
ms | @Array,
|
|
6
|
+
ms | @size > 0,
|
|
7
|
+
{"c": ms, "f": @Matrix} | @all,
|
|
8
|
+
] | @OP.and | @safe) =>
|
|
9
|
+
matrices |+ @multiply,
|
|
10
|
+
x => !{"kind": "argument_error", "origin": "stdlib", "operation": "@matrix/product", "status": 0, "input": x, "expected": ["_ ? (ms => [ms | @Array, ms | @size > 0, {\"c\": ms, \"f\": @matrix/Matrix} | @all] | @OP.and | @safe)"]}
|
|
11
|
+
)
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Rotate a 2x2 matrix by an angle in radians: the rotation matrix
|
|
2
|
+
# [[cos, -sin], [sin, cos]] multiplied onto it. Input: [angle, matrix].
|
|
3
|
+
(
|
|
4
|
+
[angle ? @Number, [[a ? @Number, b ? @Number], [c ? @Number, d ? @Number]]] =>
|
|
5
|
+
[
|
|
6
|
+
[[angle | @math.cos, angle | @math.sin | @@OP.negate], [angle | @math.sin, angle | @math.cos]],
|
|
7
|
+
[[a, b], [c, d]],
|
|
8
|
+
] | @multiply,
|
|
9
|
+
x => !{"kind": "argument_error", "origin": "stdlib", "operation": "@matrix/rotate", "status": 0, "input": x, "expected": ["[_ ? @Number, [[_ ? @Number, _ ? @Number], [_ ? @Number, _ ? @Number]]]"]}
|
|
10
|
+
)
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
# Extract the i-th (0-based) row of a matrix as a vector. Input: [matrix, index].
|
|
2
|
+
(
|
|
3
|
+
[m, i] ? ([x ? @Matrix, n ? @Integer] => n >= 0 && n < (x | @dimensions).rows) =>
|
|
4
|
+
m[i],
|
|
5
|
+
x => !{"kind": "argument_error", "origin": "stdlib", "operation": "@matrix/row", "status": 0, "input": x, "expected": ["_ ? ([m ? @matrix/Matrix, i ? @Integer] => i >= 0 && i < (m | @matrix/dimensions).rows)"]}
|
|
6
|
+
)
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
# Scale a matrix elementwise by a single number: each row scaled as a vector.
|
|
2
|
+
# Input: [number, matrix].
|
|
3
|
+
(
|
|
4
|
+
[s ? @Number, m ? @Matrix] => m |: (row => [s, row] | @vector/scale),
|
|
5
|
+
x => !{"kind": "argument_error", "origin": "stdlib", "operation": "@matrix/scale", "status": 0, "input": x, "expected": ["[_ ? @Number, _ ? @matrix/Matrix]"]}
|
|
6
|
+
)
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# Subtract the second matrix from the first, elementwise: a + (-1 * b).
|
|
2
|
+
# Input: [a, b].
|
|
3
|
+
(
|
|
4
|
+
[a, b] ? ([x ? @Matrix, y ? @Matrix] => [x, y] |: @dimensions | @OP.equal) =>
|
|
5
|
+
[a, [-1, b] | @scale] | @add,
|
|
6
|
+
x => !{"kind": "argument_error", "origin": "stdlib", "operation": "@matrix/subtract", "status": 0, "input": x, "expected": ["_ ? ([a ? @matrix/Matrix, b ? @matrix/Matrix] => [a, b] |: @matrix/dimensions | @OP.equal)"]}
|
|
7
|
+
)
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Elementwise sum of a non-empty array of equally sized matrices: a reduce
|
|
2
|
+
# over @matrix/add. The guard is a flat conditions array ending in @safe: a
|
|
3
|
+
# condition that errors (e.g. @dimensions of a non-matrix) collapses the array
|
|
4
|
+
# into that error, @safe turns it into false, and the clause just doesn't match.
|
|
5
|
+
(
|
|
6
|
+
matrices ? (ms => [
|
|
7
|
+
ms | @Array,
|
|
8
|
+
ms | @size > 0,
|
|
9
|
+
{"c": ms, "f": @Matrix} | @all,
|
|
10
|
+
ms |: @dimensions | @OP.equal,
|
|
11
|
+
] | @OP.and | @safe) =>
|
|
12
|
+
matrices |+ @add,
|
|
13
|
+
x => !{"kind": "argument_error", "origin": "stdlib", "operation": "@matrix/sum", "status": 0, "input": x, "expected": ["_ ? (ms => [ms | @Array, ms | @size > 0, {\"c\": ms, \"f\": @matrix/Matrix} | @all, ms |: @matrix/dimensions | @OP.equal] | @OP.and | @safe)"]}
|
|
14
|
+
)
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
# Transpose a matrix: its columns become its rows.
|
|
2
|
+
(
|
|
3
|
+
m ? @Matrix => (m | @dimensions).columns | @range |: (j => [m, j] | @column),
|
|
4
|
+
x => !{"kind": "argument_error", "origin": "stdlib", "operation": "@matrix/transpose", "status": 0, "input": x, "expected": ["_ ? @matrix/Matrix"]}
|
|
5
|
+
)
|
data/stdlib/range.fsn
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
(
|
|
2
2
|
0 => [],
|
|
3
|
-
n ? (m ? @Integer => [m, 0] | @OP.compare | @gt) => [...([n, -1] | @OP.sum | @), [n, -1] | @OP.sum],
|
|
4
|
-
x => !{"kind": "argument_error", "origin": "stdlib", "operation": "@range", "status": 0, "input": x, "expected": ["_ ? (m ? @Integer => [m, 0] | @OP.compare | @gte)"]}
|
|
3
|
+
n ? (m ? @Integer => [m, 0] | @OP.compare | @OP.gt) => [...([n, -1] | @OP.sum | @), [n, -1] | @OP.sum],
|
|
4
|
+
x => !{"kind": "argument_error", "origin": "stdlib", "operation": "@range", "status": 0, "input": x, "expected": ["_ ? (m ? @Integer => [m, 0] | @OP.compare | @OP.gte)"]}
|
|
5
5
|
)
|
data/stdlib/safe.fsn
ADDED
data/stdlib/sanitize.fsn
CHANGED
|
@@ -5,8 +5,7 @@
|
|
|
5
5
|
# returned unchanged.
|
|
6
6
|
(
|
|
7
7
|
v ? @Function => "<function>",
|
|
8
|
-
v ? @NonFinite => [
|
|
9
|
-
v ? @
|
|
10
|
-
v ? @Object => {"f": @sanitize, "c": v} | @map,
|
|
8
|
+
v ? @NonFinite => ["<", v | @toString, ">"] | @concat,
|
|
9
|
+
v ? @Collection => v |: @,
|
|
11
10
|
v => v
|
|
12
11
|
)
|
data/stdlib/toObject.fsn
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# Build an object from an array of [key, value] entries; later duplicate keys win.
|
|
2
|
+
# The inverse of @entries: folds the entries onto {} with the [=] setter.
|
|
3
|
+
(
|
|
4
|
+
entries ? (xs ? @Array => {"c": xs, "f": ([_ ? @String, _] => true)} | @all) =>
|
|
5
|
+
[{}, ...entries] |+ ([object, [key, value]] => object[key = value]),
|
|
6
|
+
x => !{"kind": "argument_error", "origin": "stdlib", "operation": "@toObject", "status": 0, "input": x, "expected": ["_ ? (xs ? @Array => {\"c\": xs, \"f\": ([_ ? @String, _] => true)} | @all)"]}
|
|
7
|
+
)
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
# Add two equal-length vectors elementwise: zip and sum each pair.
|
|
2
|
+
(
|
|
3
|
+
[u, v] ? ([a ? @Vector, b ? @Vector] => [a, b] |: @size | @OP.equal) =>
|
|
4
|
+
[u, v] | @zip |: @OP.sum,
|
|
5
|
+
x => !{"kind": "argument_error", "origin": "stdlib", "operation": "@vector/add", "status": 0, "input": x, "expected": ["_ ? ([u ? @vector/Vector, v ? @vector/Vector] => [u, v] |: @size | @OP.equal)"]}
|
|
6
|
+
)
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
# Cross product of two 3-dimensional vectors.
|
|
2
|
+
(
|
|
3
|
+
[[a ? @Number, b ? @Number, c ? @Number], [d ? @Number, e ? @Number, f ? @Number]] =>
|
|
4
|
+
[b * f - c * e, c * d - a * f, a * e - b * d],
|
|
5
|
+
x => !{"kind": "argument_error", "origin": "stdlib", "operation": "@vector/cross", "status": 0, "input": x, "expected": ["[[_ ? @Number, _ ? @Number, _ ? @Number], [_ ? @Number, _ ? @Number, _ ? @Number]]"]}
|
|
6
|
+
)
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
# Dot product of two equal-length vectors: zip, multiply each pair, sum.
|
|
2
|
+
(
|
|
3
|
+
[u, v] ? ([a ? @Vector, b ? @Vector] => [a, b] |: @size | @OP.equal) =>
|
|
4
|
+
[u, v] | @zip |: @OP.product | @OP.sum,
|
|
5
|
+
x => !{"kind": "argument_error", "origin": "stdlib", "operation": "@vector/dot", "status": 0, "input": x, "expected": ["_ ? ([u ? @vector/Vector, v ? @vector/Vector] => [u, v] |: @size | @OP.equal)"]}
|
|
6
|
+
)
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
# Euclidean norm (length) of a vector: the square root of the dot product with
|
|
2
|
+
# itself. Always a float.
|
|
3
|
+
(
|
|
4
|
+
v ? @Vector => [v, v] | @dot | @math.sqrt,
|
|
5
|
+
x => !{"kind": "argument_error", "origin": "stdlib", "operation": "@vector/norm", "status": 0, "input": x, "expected": ["_ ? @vector/Vector"]}
|
|
6
|
+
)
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
# Scale a vector elementwise by a single number. Input: [number, vector].
|
|
2
|
+
(
|
|
3
|
+
[s ? @Number, v ? @Vector] => v |: (entry => s * entry),
|
|
4
|
+
x => !{"kind": "argument_error", "origin": "stdlib", "operation": "@vector/scale", "status": 0, "input": x, "expected": ["[_ ? @Number, _ ? @vector/Vector]"]}
|
|
5
|
+
)
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
# Subtract the second vector from the first, elementwise: u + (-1 * v).
|
|
2
|
+
(
|
|
3
|
+
[u, v] ? ([a ? @Vector, b ? @Vector] => [a, b] |: @size | @OP.equal) =>
|
|
4
|
+
[u, [-1, v] | @scale] | @add,
|
|
5
|
+
x => !{"kind": "argument_error", "origin": "stdlib", "operation": "@vector/subtract", "status": 0, "input": x, "expected": ["_ ? ([u ? @vector/Vector, v ? @vector/Vector] => [u, v] |: @size | @OP.equal)"]}
|
|
6
|
+
)
|
data/stdlib/zip.fsn
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
# Zip a pair of equal-length arrays into an array of [left, right] pairs.
|
|
2
|
+
(
|
|
3
|
+
[xs, ys] ? ([a ? @Array, b ? @Array] => a | @size == b | @size) =>
|
|
4
|
+
xs | @size | @range |: (k => [xs[k], ys[k]]),
|
|
5
|
+
x => !{"kind": "argument_error", "origin": "stdlib", "operation": "@zip", "status": 0, "input": x, "expected": ["_ ? ([xs ? @Array, ys ? @Array] => xs | @size == ys | @size)"]}
|
|
6
|
+
)
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: fusion-lang
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0.
|
|
4
|
+
version: 0.0.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Klaus Weidinger
|
|
@@ -17,6 +17,9 @@ executables:
|
|
|
17
17
|
extensions: []
|
|
18
18
|
extra_rdoc_files: []
|
|
19
19
|
files:
|
|
20
|
+
- ".mutant.yml"
|
|
21
|
+
- ".simplecov"
|
|
22
|
+
- CHANGELOG.md
|
|
20
23
|
- LICENSE.txt
|
|
21
24
|
- README.md
|
|
22
25
|
- Rakefile
|
|
@@ -33,7 +36,11 @@ files:
|
|
|
33
36
|
- examples/factorial.fsn
|
|
34
37
|
- examples/first.fsn
|
|
35
38
|
- examples/fizzbuzz.fsn
|
|
39
|
+
- examples/gcd.fsn
|
|
36
40
|
- examples/json_test.fsn
|
|
41
|
+
- examples/matrix/OP.fsn
|
|
42
|
+
- examples/matrix/average.fsn
|
|
43
|
+
- examples/matrix/solve.fsn
|
|
37
44
|
- examples/palindrome.fsn
|
|
38
45
|
- exe/fusion
|
|
39
46
|
- lib/fusion.rb
|
|
@@ -65,18 +72,43 @@ files:
|
|
|
65
72
|
- stdlib/chars.fsn
|
|
66
73
|
- stdlib/compact.fsn
|
|
67
74
|
- stdlib/concat.fsn
|
|
75
|
+
- stdlib/entries.fsn
|
|
68
76
|
- stdlib/falsey.fsn
|
|
69
77
|
- stdlib/filter.fsn
|
|
70
78
|
- stdlib/flatten.fsn
|
|
71
|
-
- stdlib/gt.fsn
|
|
72
|
-
- stdlib/gte.fsn
|
|
73
|
-
- stdlib/lt.fsn
|
|
74
|
-
- stdlib/lte.fsn
|
|
75
79
|
- stdlib/map.fsn
|
|
80
|
+
- stdlib/matrix/Matrix.fsn
|
|
81
|
+
- stdlib/matrix/OP.fsn
|
|
82
|
+
- stdlib/matrix/add.fsn
|
|
83
|
+
- stdlib/matrix/column.fsn
|
|
84
|
+
- stdlib/matrix/determinant.fsn
|
|
85
|
+
- stdlib/matrix/dimensions.fsn
|
|
86
|
+
- stdlib/matrix/identity.fsn
|
|
87
|
+
- stdlib/matrix/invert.fsn
|
|
88
|
+
- stdlib/matrix/minor.fsn
|
|
89
|
+
- stdlib/matrix/multiply.fsn
|
|
90
|
+
- stdlib/matrix/negate.fsn
|
|
91
|
+
- stdlib/matrix/product.fsn
|
|
92
|
+
- stdlib/matrix/rotate.fsn
|
|
93
|
+
- stdlib/matrix/row.fsn
|
|
94
|
+
- stdlib/matrix/scale.fsn
|
|
95
|
+
- stdlib/matrix/subtract.fsn
|
|
96
|
+
- stdlib/matrix/sum.fsn
|
|
97
|
+
- stdlib/matrix/transpose.fsn
|
|
76
98
|
- stdlib/range.fsn
|
|
77
99
|
- stdlib/reduce.fsn
|
|
100
|
+
- stdlib/safe.fsn
|
|
78
101
|
- stdlib/sanitize.fsn
|
|
102
|
+
- stdlib/toObject.fsn
|
|
79
103
|
- stdlib/truthy.fsn
|
|
104
|
+
- stdlib/vector/Vector.fsn
|
|
105
|
+
- stdlib/vector/add.fsn
|
|
106
|
+
- stdlib/vector/cross.fsn
|
|
107
|
+
- stdlib/vector/dot.fsn
|
|
108
|
+
- stdlib/vector/norm.fsn
|
|
109
|
+
- stdlib/vector/scale.fsn
|
|
110
|
+
- stdlib/vector/subtract.fsn
|
|
111
|
+
- stdlib/zip.fsn
|
|
80
112
|
homepage: https://github.com/dunkelziffer/fusion
|
|
81
113
|
licenses:
|
|
82
114
|
- MIT
|
data/stdlib/gt.fsn
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
# Strictly greater: interprets an @OP.compare result. Use as `[a, b] | @OP.compare | @gt`.
|
|
2
|
-
# A partial order's compare may return null (incomparable); that propagates as null.
|
|
3
|
-
(
|
|
4
|
-
-1 => false,
|
|
5
|
-
0 => false,
|
|
6
|
-
1 => true,
|
|
7
|
-
null => null,
|
|
8
|
-
x => !{"kind": "argument_error", "origin": "stdlib", "operation": "@gt", "status": 0, "input": x, "expected": ["-1", "0", "1", "null"]},
|
|
9
|
-
)
|
data/stdlib/gte.fsn
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
# Greater-or-equal: interprets an @OP.compare result. Use as `[a, b] | @OP.compare | @gte`.
|
|
2
|
-
# A partial order's compare may return null (incomparable); that propagates as null.
|
|
3
|
-
(
|
|
4
|
-
-1 => false,
|
|
5
|
-
0 => true,
|
|
6
|
-
1 => true,
|
|
7
|
-
null => null,
|
|
8
|
-
x => !{"kind": "argument_error", "origin": "stdlib", "operation": "@gte", "status": 0, "input": x, "expected": ["-1", "0", "1", "null"]},
|
|
9
|
-
)
|
data/stdlib/lt.fsn
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
# Strictly less: interprets an @OP.compare result. Use as `[a, b] | @OP.compare | @lt`.
|
|
2
|
-
# A partial order's compare may return null (incomparable); that propagates as null.
|
|
3
|
-
(
|
|
4
|
-
-1 => true,
|
|
5
|
-
0 => false,
|
|
6
|
-
1 => false,
|
|
7
|
-
null => null,
|
|
8
|
-
x => !{"kind": "argument_error", "origin": "stdlib", "operation": "@lt", "status": 0, "input": x, "expected": ["-1", "0", "1", "null"]},
|
|
9
|
-
)
|
data/stdlib/lte.fsn
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
# Less-or-equal: interprets an @OP.compare result. Use as `[a, b] | @OP.compare | @lte`.
|
|
2
|
-
# A partial order's compare may return null (incomparable); that propagates as null.
|
|
3
|
-
(
|
|
4
|
-
-1 => true,
|
|
5
|
-
0 => true,
|
|
6
|
-
1 => false,
|
|
7
|
-
null => null,
|
|
8
|
-
x => !{"kind": "argument_error", "origin": "stdlib", "operation": "@lte", "status": 0, "input": x, "expected": ["-1", "0", "1", "null"]},
|
|
9
|
-
)
|