Skip to content

Commit 5828ff2

Browse files
committed
Rejigger flow's signature
This is objectively worse, but will make sense with infix notation.
1 parent cda2dc1 commit 5828ff2

File tree

5 files changed

+76
-199
lines changed

5 files changed

+76
-199
lines changed
Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
{@runtime, context =>
2-
:flow({
3-
:context.arguments.lookup
2+
:flow(
43
:match({
54
none: {}
6-
some: :flow({
7-
:context.environment.lookup
5+
some: :flow(
86
:match({
97
none: {}
108
some: :identity
119
})
12-
})
10+
)(
11+
:context.environment.lookup
12+
)
1313
})
14-
})(variable)
14+
)(
15+
:context.arguments.lookup
16+
)(variable)
1517
}

src/end-to-end.test.ts

Lines changed: 15 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ testCases(endToEnd, code => code)('end-to-end tests', [
133133
],
134134
[':match({ a: A })({ tag: a, value: {} })', either.makeRight('A')],
135135
[':atom.prepend(a)(b)', either.makeRight('ab')],
136-
[':flow({ :atom.append(a), :atom.append(b) })(z)', either.makeRight('zab')],
136+
[':flow(:atom.append(b))(:atom.append(a))(z)', either.makeRight('zab')],
137137
[
138138
`{
139139
// foo: bar
@@ -159,42 +159,21 @@ testCases(endToEnd, code => code)('end-to-end tests', [
159159
either.makeRight({ tag: 'none', value: {} }),
160160
],
161161
[
162-
`{@runtime, {@apply, :flow, {
163-
{@apply, :object.lookup, environment}
164-
{@apply, :match, {
165-
none: "environment does not exist"
166-
some: {@apply, :flow, {
167-
{@apply, :object.lookup, lookup}
168-
{@apply, :match, {
169-
none: "environment.lookup does not exist"
170-
some: {@apply, :apply, PATH}
171-
}}
172-
}}
173-
}}
174-
}}}`,
175-
output => {
176-
if (either.isLeft(output)) {
177-
assert.fail(output.value.message)
178-
}
179-
assert(typeof output.value === 'object')
180-
assert.deepEqual(output.value['tag'], 'some')
181-
assert.deepEqual(typeof output.value['value'], 'string')
182-
},
183-
],
184-
[
185-
`{@runtime, :flow({
186-
:object.lookup(environment)
187-
:match({
188-
none: "environment does not exist"
189-
some: :flow({
190-
:object.lookup(lookup)
191-
:match({
192-
none: "environment.lookup does not exist"
193-
some: :apply(PATH)
194-
})
162+
`{@runtime, :flow(
163+
:match({
164+
none: "environment does not exist"
165+
some: :flow(
166+
:match({
167+
none: "environment.lookup does not exist"
168+
some: :apply(PATH)
169+
})
170+
)(
171+
:object.lookup(lookup)
172+
)
195173
})
196-
})
197-
})}`,
174+
)(
175+
:object.lookup(environment)
176+
)}`,
198177
output => {
199178
if (either.isLeft(output)) {
200179
assert.fail(output.value.message)

src/language/compiling/compiler.test.ts

Lines changed: 8 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -21,51 +21,18 @@ testCases(compile, input => `compiling \`${JSON.stringify(input)}\``)(
2121
{
2222
true1: ['@check', true, ['@lookup', 'identity']],
2323
true2: ['@apply', ['@index', ['@lookup', 'boolean'], ['not']], false],
24-
true3: [
25-
'@apply',
26-
[
27-
'@apply',
28-
['@lookup', 'flow'],
29-
[
30-
['@index', ['@lookup', 'boolean'], ['not']],
31-
['@index', ['@lookup', 'boolean'], ['not']],
32-
],
33-
],
34-
true,
35-
],
3624
false1: ['@check', false, ['@index', ['@lookup', 'boolean'], ['is']]],
3725
false2: [
3826
'@apply',
3927
['@index', ['@lookup', 'boolean'], ['is']],
4028
'not a boolean',
4129
],
42-
false3: [
43-
'@apply',
44-
[
45-
'@apply',
46-
['@lookup', 'flow'],
47-
[
48-
[
49-
'@apply',
50-
['@lookup', 'flow'],
51-
[
52-
['@index', ['@lookup', 'boolean'], ['not']],
53-
['@index', ['@lookup', 'boolean'], ['not']],
54-
],
55-
],
56-
['@index', ['@lookup', 'boolean'], ['not']],
57-
],
58-
],
59-
true,
60-
],
6130
},
6231
success({
6332
true1: 'true',
6433
true2: 'true',
65-
true3: 'true',
6634
false1: 'false',
6735
false2: 'false',
68-
false3: 'false',
6936
}),
7037
],
7138
[
@@ -116,37 +83,25 @@ testCases(compile, input => `compiling \`${JSON.stringify(input)}\``)(
11683
'@runtime',
11784
[
11885
'@apply',
119-
['@lookup', 'flow'],
120-
[
121-
['@lookup', 'identity'],
122-
['@lookup', 'identity'],
123-
],
86+
['@apply', ['@lookup', 'flow'], ['@lookup', 'identity']],
87+
['@lookup', 'identity'],
12488
],
12589
],
12690
success({
12791
0: '@runtime',
12892
function: {
12993
0: '@apply',
130-
function: { 0: '@lookup', key: 'flow' },
131-
argument: {
132-
0: { 0: '@lookup', key: 'identity' },
133-
1: { 0: '@lookup', key: 'identity' },
94+
function: {
95+
0: '@apply',
96+
function: { 0: '@lookup', key: 'flow' },
97+
argument: { 0: '@lookup', key: 'identity' },
13498
},
99+
argument: { 0: '@lookup', key: 'identity' },
135100
},
136101
}),
137102
],
138103
[
139-
[
140-
'@runtime',
141-
[
142-
'@apply',
143-
['@lookup', 'flow'],
144-
[
145-
['@index', ['@lookup', 'boolean'], ['not']],
146-
['@index', ['@lookup', 'boolean'], ['not']],
147-
],
148-
],
149-
],
104+
['@runtime', ['@index', ['@lookup', 'boolean'], ['not']]],
150105
output => {
151106
assert(either.isLeft(output))
152107
assert(output.value.kind === 'typeMismatch')

src/language/runtime/evaluator.test.ts

Lines changed: 0 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -17,56 +17,6 @@ testCases(evaluate, input => `evaluating \`${JSON.stringify(input)}\``)(
1717
[
1818
['Hello, world!', success('Hello, world!')],
1919
[['@check', true, ['@lookup', 'identity']], success('true')],
20-
[
21-
[
22-
'@runtime',
23-
[
24-
'@apply',
25-
['@lookup', 'flow'],
26-
[
27-
[
28-
'@apply',
29-
['@index', ['@lookup', 'object'], ['lookup']],
30-
'environment',
31-
],
32-
[
33-
'@apply',
34-
['@lookup', 'match'],
35-
{
36-
none: 'environment does not exist!',
37-
some: [
38-
'@apply',
39-
['@lookup', 'flow'],
40-
[
41-
[
42-
'@apply',
43-
['@index', ['@lookup', 'object'], ['lookup']],
44-
'lookup',
45-
],
46-
[
47-
'@apply',
48-
['@lookup', 'match'],
49-
{
50-
none: 'environment.lookup does not exist!',
51-
some: ['@apply', ['@lookup', 'apply'], 'PATH'],
52-
},
53-
],
54-
],
55-
],
56-
},
57-
],
58-
],
59-
],
60-
],
61-
output => {
62-
if (either.isLeft(output)) {
63-
assert.fail(output.value.message)
64-
}
65-
assert(typeof output.value === 'object')
66-
assert(output.value['tag'] === 'some')
67-
assert(typeof output.value['value'] === 'string')
68-
},
69-
],
7020
[
7121
['@check', 'not a boolean', ['@index', ['@lookup', 'boolean'], 'is']],
7222
output => assert(either.isLeft(output)),

src/language/semantics/stdlib/global-functions.ts

Lines changed: 45 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,18 @@ import { isFunctionNode, makeFunctionNode } from '../function-node.js'
55
import {
66
isObjectNode,
77
lookupPropertyOfObjectNode,
8-
makeObjectNode,
98
type ObjectNode,
109
} from '../object-node.js'
1110
import { isSemanticGraph, type SemanticGraph } from '../semantic-graph.js'
1211
import { types } from '../type-system.js'
1312
import {
1413
makeFunctionType,
15-
makeObjectType,
1614
makeTypeParameter,
1715
} from '../type-system/type-formats.js'
1816
import {
1917
preludeFunction,
2018
serializeOnceAppliedFunction,
19+
serializeTwiceAppliedFunction,
2120
} from './stdlib-utilities.js'
2221

2322
const A = makeTypeParameter('a', { assignableTo: types.something })
@@ -75,66 +74,58 @@ export const globalFunctions = {
7574
),
7675
),
7776

78-
// { 0: a => b, 1: b => c } => (a => c)
77+
// (b => c) => (a => b) => (a => c)
7978
flow: preludeFunction(
8079
['flow'],
8180
{
82-
parameter: makeObjectType('', {
83-
0: makeFunctionType('', {
84-
parameter: A,
85-
return: B,
86-
}),
87-
1: makeFunctionType('', {
88-
parameter: B,
89-
return: C,
90-
}),
91-
}),
92-
return: makeFunctionType('', {
93-
parameter: A,
94-
return: C,
95-
}),
81+
// TODO
82+
parameter: types.something,
83+
return: types.something,
9684
},
97-
argument => {
98-
if (!isObjectNode(argument)) {
85+
secondFunction => {
86+
if (!isFunctionNode(secondFunction)) {
9987
return either.makeLeft({
10088
kind: 'panic',
101-
message: '`flow` must be given an object',
89+
message: 'argument must be a function',
10290
})
10391
} else {
104-
const argument0 = lookupPropertyOfObjectNode('0', argument)
105-
const argument1 = lookupPropertyOfObjectNode('1', argument)
106-
if (option.isNone(argument0) || option.isNone(argument1)) {
107-
return either.makeLeft({
108-
kind: 'panic',
109-
message:
110-
"`flow`'s argument must contain properties named '0' and '1'",
111-
})
112-
} else if (
113-
!isFunctionNode(argument0.value) ||
114-
!isFunctionNode(argument1.value)
115-
) {
116-
return either.makeLeft({
117-
kind: 'panic',
118-
message: "`flow`'s argument must contain functions",
119-
})
120-
} else {
121-
const function0 = argument0.value
122-
const function1 = argument1.value
123-
return either.makeRight(
124-
makeFunctionNode(
125-
{
126-
parameter: function0.signature.parameter,
127-
return: function1.signature.parameter,
128-
},
129-
serializeOnceAppliedFunction(
130-
['flow'],
131-
makeObjectNode({ 0: function0, 1: function1 }),
132-
),
133-
option.none,
134-
argument => either.flatMap(function0(argument), function1),
135-
),
136-
)
137-
}
92+
return either.makeRight(
93+
makeFunctionNode(
94+
{
95+
// TODO
96+
parameter: types.something,
97+
return: types.something,
98+
},
99+
serializeOnceAppliedFunction(['flow'], secondFunction),
100+
option.none,
101+
firstFunction => {
102+
if (!isFunctionNode(firstFunction)) {
103+
return either.makeLeft({
104+
kind: 'panic',
105+
message: 'argument must be a function',
106+
})
107+
} else {
108+
return either.makeRight(
109+
makeFunctionNode(
110+
{
111+
// TODO
112+
parameter: types.something,
113+
return: types.something,
114+
},
115+
serializeTwiceAppliedFunction(
116+
['flow'],
117+
secondFunction,
118+
firstFunction,
119+
),
120+
option.none,
121+
argument =>
122+
either.flatMap(firstFunction(argument), secondFunction),
123+
),
124+
)
125+
}
126+
},
127+
),
128+
)
138129
}
139130
},
140131
),

0 commit comments

Comments
 (0)