Function definition evaluated

This commit is contained in:
Umur Ozkul 2022-04-25 02:37:35 +02:00
parent 1f989de11c
commit e3ef08839f
6 changed files with 42 additions and 30 deletions

View File

@ -7,6 +7,6 @@ describe("Parse function assignment", () => {
//MathJs does not allow blocks in function definitions //MathJs does not allow blocks in function definitions
}) })
Skip.describe("Evaluate function assignment", () => { describe("Evaluate function assignment", () => {
testParseToBe("f(x)=x; f(1)", "Ok(1)") testEvalToBe("f(x)=x; f(1)", "Ok(1)")
}) })

View File

@ -20,28 +20,29 @@ let rec replaceSymbols = (expression: expression, bindings: ExpressionT.bindings
expression, expression,
errorValue, errorValue,
> => { > => {
let getParameters = (bindings: ExpressionT.bindings): list<string> => { let getParameters = (bindings: ExpressionT.bindings): array<string> => {
let eParameters = Belt.Map.String.getWithDefault(bindings, "$parameters", EParameters(list{})) let eParameters = Belt.Map.String.getWithDefault(bindings, "$parameters", EParameters([]))
switch eParameters { switch eParameters {
| EParameters(parameters) => parameters | EParameters(parameters) => parameters
| _ => list{} | _ => []
} }
} }
let putParameters = ( let putParameters = (
bindings: ExpressionT.bindings, bindings: ExpressionT.bindings,
parameters: list<string>, parameters: array<string>,
): ExpressionT.bindings => ): ExpressionT.bindings =>
Belt.Map.String.set(bindings, "$parameters", ExpressionT.EParameters(parameters)) Belt.Map.String.set(bindings, "$parameters", ExpressionT.EParameters(parameters))
switch expression { switch expression {
| ExpressionT.EValue(EvSymbol(aSymbol)) => { | ExpressionT.EValue(EvSymbol(aSymbol)) => {
let parameters = getParameters(bindings) let parameters = getParameters(bindings)
switch Belt.List.has(parameters, aSymbol, (a, b) => a == b) { switch Js.Array2.some(parameters, a => a == aSymbol) {
| true => expression->Ok // We cannot bind the parameters with global values | true => expression->Ok // We cannot bind the parameters with global values
| false => | false =>
switch bindings->Belt.Map.String.get(aSymbol) { switch bindings->Belt.Map.String.get(aSymbol) {
| Some(boundExpression) => boundExpression->Ok | Some(boundExpression) => boundExpression->Ok
| None => RESymbolNotFound(aSymbol)->Error | None => RESymbolNotFound(aSymbol)->Error
} }
} }
} }
@ -54,14 +55,16 @@ let rec replaceSymbols = (expression: expression, bindings: ExpressionT.bindings
expr, expr,
}) => { }) => {
let oldParameters = getParameters(bindings) let oldParameters = getParameters(bindings)
let newParameters = oldParameters->Belt.List.concat(parameters) let newParameters = oldParameters->Js.Array2.concat(parameters)
let newBindings = putParameters(bindings, newParameters) let newBindings = putParameters(bindings, newParameters)
let rNewExpr = replaceSymbols(expr, newBindings) let rNewExpr = replaceSymbols(expr, newBindings)
rNewExpr -> Result.flatMap(newExpr => ExpressionT.EList(list{ rNewExpr->Result.flatMap(newExpr =>
ExpressionT.EValue(EvCall("$lambda")), ExpressionT.EList(list{
ExpressionT.EParameters(parameters), ExpressionT.EValue(EvCall("$lambda")),
newExpr ExpressionT.EParameters(parameters),
})->Ok) newExpr,
})->Ok
)
} }
| ExpressionT.EList(list) => { | ExpressionT.EList(list) => {
let racc = list->Belt.List.reduceReverse(Ok(list{}), (racc, each: expression) => let racc = list->Belt.List.reduceReverse(Ok(list{}), (racc, each: expression) =>
@ -77,13 +80,12 @@ let rec replaceSymbols = (expression: expression, bindings: ExpressionT.bindings
} }
} }
} }
let dispatchMacroCall = ( let dispatchMacroCall = (
list: list<expression>, list: list<expression>,
bindings: ExpressionT.bindings, bindings: ExpressionT.bindings,
reduceExpression: reducerFn, reduceExpression: reducerFn,
): result<expression, 'e> => { ): result<expression, 'e> => {
let doBindStatement = (statement: expression, bindings: ExpressionT.bindings) => { let doBindStatement = (statement: expression, bindings: ExpressionT.bindings) => {
switch statement { switch statement {
| ExpressionT.EList(list{ | ExpressionT.EList(list{

View File

@ -8,15 +8,19 @@ open Reducer_ErrorValue
type expression = T.expression type expression = T.expression
type expressionValue = ExpressionValue.expressionValue type expressionValue = ExpressionValue.expressionValue
type internalCode = ExpressionValue.internalCode
type t = expression type t = expression
external castExpressionToInternalCode: expression => internalCode = "%identity"
external castInternalCodeToInternalCode: internalCode => expression = "%identity"
/* /*
Shows the expression as text of expression Shows the expression as text of expression
*/ */
let rec toString = expression => let rec toString = expression =>
switch expression { switch expression {
| T.EBindings(_) => "$$bound" | T.EBindings(_) => "$$bound"
| T.EParameters(params) => `(${Js.Array2.toString(params->Belt.List.toArray)})` | T.EParameters(params) => `(${Js.Array2.toString(params)})`
| T.EList(aList) => | T.EList(aList) =>
`(${Belt.List.map(aList, aValue => toString(aValue)) `(${Belt.List.map(aList, aValue => toString(aValue))
->Extra.List.interperse(" ") ->Extra.List.interperse(" ")
@ -93,9 +97,11 @@ let rec reduceExpression = (expression: t, bindings: T.bindings): result<express
let rec reduceExpandedExpression = (expression: t): result<expressionValue, 'e> => let rec reduceExpandedExpression = (expression: t): result<expressionValue, 'e> =>
switch expression { switch expression {
// | T.EList(list{T.EValue(EvCall("$lambda")), T.EParameters(parameters), functionDefinition}) => { | T.EList(list{
// let lambda = T.ELambda(parameters, functionDefinition) T.EValue(EvCall("$lambda")),
// lambda->Ok} T.EParameters(parameters),
functionDefinition,
}) => EvLambda(parameters, functionDefinition->castExpressionToInternalCode)->Ok
| T.EValue(value) => value->Ok | T.EValue(value) => value->Ok
| T.EList(list) => { | T.EList(list) => {
let racc: result<list<expressionValue>, 'e> = list->Belt.List.reduceReverse(Ok(list{}), ( let racc: result<list<expressionValue>, 'e> = list->Belt.List.reduceReverse(Ok(list{}), (
@ -113,7 +119,8 @@ let rec reduceExpression = (expression: t, bindings: T.bindings): result<express
racc->Result.flatMap(acc => acc->reduceValueList) racc->Result.flatMap(acc => acc->reduceValueList)
} }
| EBindings(_bindings) => RETodo("Error: Bindings cannot be reduced to values")->Error | EBindings(_bindings) => RETodo("Error: Bindings cannot be reduced to values")->Error
| EParameters(_parameters) => RETodo("Error: Lambda Parameters cannot be reduced to values")->Error | EParameters(_parameters) =>
RETodo("Error: Lambda Parameters cannot be reduced to values")->Error
} }
let rExpandedExpression: result<t, 'e> = expression->seekMacros(bindings) let rExpandedExpression: result<t, 'e> = expression->seekMacros(bindings)
@ -142,7 +149,9 @@ let evalPartialUsingExternalBindings_ = (codeText: string, bindings: T.bindings)
Therefore all statments are assignments. Therefore all statments are assignments.
*/ */
let evalOuterWBindings_ = (codeText: string, bindings: T.bindings) => { let evalOuterWBindings_ = (codeText: string, bindings: T.bindings) => {
parseOuter(codeText)->Result.flatMap(expression => expression->evalUsingExternalBindingsExpression_(bindings)) parseOuter(codeText)->Result.flatMap(expression =>
expression->evalUsingExternalBindingsExpression_(bindings)
)
} }
/* /*

View File

@ -12,5 +12,5 @@ type rec expression =
| EList(list<expression>) // A list to map-reduce | EList(list<expression>) // A list to map-reduce
| EValue(expressionValue) // Irreducible built-in value. Reducer should not know the internals. External libraries are responsible | EValue(expressionValue) // Irreducible built-in value. Reducer should not know the internals. External libraries are responsible
| EBindings(bindings) // $let kind of statements return bindings; for internal use only | EBindings(bindings) // $let kind of statements return bindings; for internal use only
| EParameters(list<string>) // for $defun; for internal use only | EParameters(array<string>) // for $defun; for internal use only
and bindings = Belt.Map.String.t<expression> and bindings = Belt.Map.String.t<expression>

View File

@ -104,7 +104,7 @@ let rec fromNode = (mathJsNode: Parse.node): result<expression, errorValue> =>
let rValueExpression = fromNode(faNode["expr"]) let rValueExpression = fromNode(faNode["expr"])
rValueExpression->Result.flatMap(valueExpression => { rValueExpression->Result.flatMap(valueExpression => {
let lispParams = faNode["params"]->Belt.List.fromArray->ExpressionT.EParameters let lispParams = faNode["params"]->ExpressionT.EParameters
let rLambda = passToFunction("$lambda", list{lispParams, valueExpression}->Ok) let rLambda = passToFunction("$lambda", list{lispParams, valueExpression}->Ok)
rLambda->Result.flatMap(lambda => { rLambda->Result.flatMap(lambda => {
passToFunction("$let", list{symbol, lambda}->Ok) passToFunction("$let", list{symbol, lambda}->Ok)

View File

@ -56,14 +56,15 @@ and toStringRecord = aRecord => {
let toStringWithType = aValue => let toStringWithType = aValue =>
switch aValue { switch aValue {
| EvArray(_) => `Array::${toString(aValue)}`
| EvBool(_) => `Bool::${toString(aValue)}` | EvBool(_) => `Bool::${toString(aValue)}`
| EvCall(_) => `Call::${toString(aValue)}` | EvCall(_) => `Call::${toString(aValue)}`
| EvDistribution(_) => `Distribution::${toString(aValue)}`
| EvLambda(_parameters, _internalCode) => `Lambda::${toString(aValue)}`
| EvNumber(_) => `Number::${toString(aValue)}` | EvNumber(_) => `Number::${toString(aValue)}`
| EvRecord(_) => `Record::${toString(aValue)}`
| EvString(_) => `String::${toString(aValue)}` | EvString(_) => `String::${toString(aValue)}`
| EvSymbol(_) => `Symbol::${toString(aValue)}` | EvSymbol(_) => `Symbol::${toString(aValue)}`
| EvArray(_) => `Array::${toString(aValue)}`
| EvRecord(_) => `Record::${toString(aValue)}`
| EvDistribution(_) => `Distribution::${toString(aValue)}`
} }
let argsToString = (args: array<expressionValue>): string => { let argsToString = (args: array<expressionValue>): string => {