Skip to content

Commit 5420e6c

Browse files
move to obj for call obj args, add scratch for tracing and building blocks for chainRule
1 parent 323a550 commit 5420e6c

6 files changed

Lines changed: 150 additions & 54 deletions

File tree

src/schemas/objs/call.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,21 @@
22

33
import { Schema } from "effect";
44
import type { BuiltInFunc } from "../built-in";
5-
import { Exp } from "../nodes/exps/union";
5+
import type { Exp } from "../nodes/exps/union";
66
import { BuiltInObj } from "./built-in";
77
import { FunctionObj, type FunctionObjEncoded } from "./function";
8+
import { Obj, type ObjEncoded } from "./union";
89

910
export interface CallObj {
1011
readonly _tag: "CallObj";
1112
readonly fn: FunctionObj | BuiltInObj;
12-
readonly args: readonly Exp[];
13+
readonly args: readonly Obj[];
1314
}
1415

1516
export interface CallObjEncoded {
1617
readonly _tag: "CallObj";
1718
readonly fn: FunctionObjEncoded | BuiltInObj;
18-
readonly args: readonly Exp[];
19+
readonly args: readonly ObjEncoded[];
1920
}
2021

2122
export const CallObj = Schema.TaggedStruct("CallObj", {
@@ -25,10 +26,10 @@ export const CallObj = Schema.TaggedStruct("CallObj", {
2526
FunctionObjEncoded | BuiltInObj
2627
> => Schema.Union(FunctionObj, BuiltInObj),
2728
),
28-
args: Schema.Array(Schema.suspend((): Schema.Schema<Exp> => Exp)),
29+
args: Schema.Array(Schema.suspend((): Schema.Schema<Obj, ObjEncoded> => Obj)),
2930
});
3031

31-
export const BuiltInCallObj = (fn: BuiltInFunc) => (args: readonly Exp[]) =>
32+
export const BuiltInCallObj = (fn: BuiltInFunc) => (args: readonly Obj[]) =>
3233
CallObj.make({
3334
fn: BuiltInObj.make({ fn }),
3435
args,

src/scratch/trace-scratch.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { defaultLayer } from "@/layers/default";
2+
import { Evaluator } from "@/services/evaluator";
3+
import { objInspect } from "@/services/object";
4+
import { Parser } from "@/services/parser";
5+
import { NodeSdk } from "@effect/opentelemetry";
6+
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
7+
import { BatchSpanProcessor } from "@opentelemetry/sdk-trace-base";
8+
import { Effect, Layer, ManagedRuntime } from "effect";
9+
10+
// Create a program with tasks and subtasks
11+
const exampleProgram = Effect.gen(function* () {
12+
const evaluator = yield* Evaluator;
13+
return yield* evaluator.run("diff(fn(x) { sin(3 * x + 2) })(0)");
14+
}).pipe(Effect.provide(defaultLayer));
15+
16+
const NodeSdkLive = NodeSdk.layer(() => ({
17+
resource: { serviceName: "example" },
18+
spanProcessor: new BatchSpanProcessor(new OTLPTraceExporter()),
19+
}));
20+
21+
Effect.runPromise(
22+
exampleProgram.pipe(
23+
Effect.provide(NodeSdkLive),
24+
Effect.catchAllCause(Effect.logError),
25+
),
26+
);
27+
28+
const program = (input: string) =>
29+
Effect.gen(function* () {
30+
const evaluator = yield* Evaluator;
31+
const returnValue = yield* evaluator.runAndInterpret(input);
32+
const evaluated = objInspect(returnValue.evaluation);
33+
return evaluated;
34+
});
35+
36+
ManagedRuntime.make(
37+
Layer.mergeAll(Parser.Default, Evaluator.Default),
38+
).runPromise(
39+
program("diff(fn (x) { 1 / (2 * x + 3) })(3)").pipe(
40+
Effect.provide(NodeSdkLive),
41+
Effect.catchAllCause(Effect.logError),
42+
),
43+
);

src/services/diff/helper.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,14 @@ import { BlockStmt } from "@/schemas/nodes/stmts/block";
44
import { ExpStmt } from "@/schemas/nodes/stmts/exp";
55
import { CallObj } from "@/schemas/objs/call";
66
import { FunctionObj } from "@/schemas/objs/function";
7+
import type { Obj } from "@/schemas/objs/union";
78
import type { PolynomialObj } from "@/schemas/objs/unions/polynomials";
89
import { Effect } from "effect";
910
import { createEnvironment } from "../object/environment";
1011

1112
export const makeLambda = (
1213
x: IdentExp,
13-
args: readonly Exp[],
14+
args: readonly Obj[],
1415
expression: Exp,
1516
): Effect.Effect<PolynomialObj, never, never> =>
1617
Effect.succeed(

src/services/diff/obj.ts

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,39 @@ const baseBuiltInDiffFunc =
3838
Match.when("sin", () =>
3939
Schema.decodeUnknown(PolynomialObj)(args[0]).pipe(
4040
Effect.flatMap((g) =>
41-
chainRule(
42-
CallObj.make({
43-
fn: BuiltInObj.make({ fn: "cos" }),
44-
args,
45-
}),
46-
g,
47-
x,
41+
Match.value(g).pipe(
42+
Match.tag("IdentObj", () =>
43+
Effect.succeed(
44+
CallObj.make({
45+
fn: BuiltInObj.make({ fn: "cos" }),
46+
args,
47+
}),
48+
),
49+
),
50+
Match.tag("IntegerObj", () =>
51+
Effect.succeed(
52+
CallObj.make({
53+
fn: BuiltInObj.make({ fn: "cos" }),
54+
args,
55+
}),
56+
),
57+
),
58+
Match.orElse(() =>
59+
Effect.gen(function* () {
60+
yield* Effect.log(
61+
`Differentiating sin with arg type: ${g._tag}`,
62+
);
63+
const chain = yield* chainRule(
64+
CallObj.make({
65+
fn: BuiltInObj.make({ fn: "sin" }),
66+
args: [IdentObj.make({ identExp: x })],
67+
}),
68+
g,
69+
x,
70+
);
71+
return chain;
72+
}),
73+
),
4874
),
4975
),
5076
),
@@ -106,6 +132,7 @@ const baseBuiltInDiffFunc =
106132
),
107133
),
108134
),
135+
Effect.withSpan("diff.built_in"),
109136
);
110137

111138
const processTerm = (exp: PolynomialObj, x: IdentExp) =>
@@ -169,6 +196,7 @@ const processTerm = (exp: PolynomialObj, x: IdentExp) =>
169196
),
170197
Match.tag("CallObj", baseBuiltInDiffFunc(x)),
171198
Match.exhaustive,
199+
Effect.withSpan("diff.process_term"),
172200
);
173201

174202
export const diffPolynomial = (
@@ -225,4 +253,5 @@ export const diffPolynomial = (
225253
),
226254
),
227255
Match.exhaustive,
256+
Effect.withSpan("diff.outer"),
228257
);

src/services/evaluator/index.ts

Lines changed: 51 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -229,49 +229,59 @@ export const evalDiff = (diffExp: DiffExp) => (env: Environment) =>
229229
),
230230
),
231231
Match.tag("CallObj", ({ fn, args }) =>
232-
Effect.succeed(
233-
CallExp.make({
234-
token: { _tag: "fn", literal: "fn" },
235-
fn: FuncExp.make({
236-
token: { _tag: "fn", literal: "fn" },
237-
parameters: diffExp.params, // LIMITATION TO A SINGLE VARIABLE FUNCTIONS.
238-
body: BlockStmt.make({
239-
token: { _tag: "!", literal: "!" }, // FIX eventually
240-
statements: [
241-
ExpStmt.make({
242-
token: {
243-
_tag: "!",
244-
literal: "!",
245-
},
246-
expression: CallExp.make({
247-
token: {
248-
_tag: "!",
249-
literal: "!",
250-
},
251-
fn: Match.value(fn).pipe(
252-
Match.tag("BuiltInObj", ({ fn }) =>
253-
IdentExp.make({
254-
token: { _tag: "IDENT", literal: fn },
255-
value: fn,
256-
}),
257-
),
258-
Match.tag("FunctionObj", ({ params, body }) =>
259-
FuncExp.make({
260-
token: fnTokenSchema.make({ literal: "fn" }),
261-
parameters: params,
262-
body,
263-
}),
264-
),
265-
Match.exhaustive,
266-
),
267-
args,
268-
}),
232+
Effect.all(
233+
args.map((arg) =>
234+
Schema.decodeUnknown(PolynomialObj)(arg).pipe(
235+
Effect.flatMap(convertToExp),
236+
),
237+
),
238+
).pipe(
239+
Effect.flatMap((args) =>
240+
Effect.succeed(
241+
CallExp.make({
242+
token: { _tag: "fn", literal: "fn" },
243+
fn: FuncExp.make({
244+
token: { _tag: "fn", literal: "fn" },
245+
parameters: diffExp.params, // LIMITATION TO A SINGLE VARIABLE FUNCTIONS.
246+
body: BlockStmt.make({
247+
token: { _tag: "!", literal: "!" }, // FIX eventually
248+
statements: [
249+
ExpStmt.make({
250+
token: {
251+
_tag: "!",
252+
literal: "!",
253+
},
254+
expression: CallExp.make({
255+
token: {
256+
_tag: "!",
257+
literal: "!",
258+
},
259+
fn: Match.value(fn).pipe(
260+
Match.tag("BuiltInObj", ({ fn }) =>
261+
IdentExp.make({
262+
token: { _tag: "IDENT", literal: fn },
263+
value: fn,
264+
}),
265+
),
266+
Match.tag("FunctionObj", ({ params, body }) =>
267+
FuncExp.make({
268+
token: fnTokenSchema.make({ literal: "fn" }),
269+
parameters: params,
270+
body,
271+
}),
272+
),
273+
Match.exhaustive,
274+
),
275+
args,
276+
}),
277+
}),
278+
],
269279
}),
270-
],
280+
}),
281+
args,
271282
}),
272-
}),
273-
args,
274-
}),
283+
),
284+
),
275285
),
276286
),
277287
Match.exhaustive,

src/tests/vitest/eval/eval.test.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,17 @@ describe("eval", () => {
414414
);
415415
}
416416
});
417+
describe("trig constant", () => {
418+
const tests = [["diff(fn(x) {sin(2)})(0)", 0]] as const;
419+
420+
for (const [input, expected] of tests) {
421+
it.effect(input, () =>
422+
evalP(input).pipe(
423+
Effect.flatMap((evaluated) => expectIntObjEq(evaluated, expected)),
424+
),
425+
);
426+
}
427+
});
417428
describe("trig", () => {
418429
const tests = [
419430
["diff(fn(x) {sin(x)})(0)", Math.cos(0)],
@@ -436,6 +447,7 @@ describe("eval", () => {
436447
describe("trig chain", () => {
437448
const tests = [
438449
["diff(fn(x) { sin(3 * x + 2) })(0)", 3 * Math.cos(3 * 0 + 2)],
450+
["diff(fn(x) { 3 * x + 2 })(0)", 3],
439451
] as const;
440452

441453
for (const [input, expected] of tests) {

0 commit comments

Comments
 (0)