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
})
Skip.describe("Evaluate function assignment", () => {
testParseToBe("f(x)=x; f(1)", "Ok(1)")
})
describe("Evaluate function assignment", () => {
testEvalToBe("f(x)=x; f(1)", "Ok(1)")
})

View File

@ -20,28 +20,29 @@ let rec replaceSymbols = (expression: expression, bindings: ExpressionT.bindings
expression,
errorValue,
> => {
let getParameters = (bindings: ExpressionT.bindings): list<string> => {
let eParameters = Belt.Map.String.getWithDefault(bindings, "$parameters", EParameters(list{}))
let getParameters = (bindings: ExpressionT.bindings): array<string> => {
let eParameters = Belt.Map.String.getWithDefault(bindings, "$parameters", EParameters([]))
switch eParameters {
| EParameters(parameters) => parameters
| _ => list{}
| _ => []
}
}
let putParameters = (
bindings: ExpressionT.bindings,
parameters: list<string>,
parameters: array<string>,
): ExpressionT.bindings =>
Belt.Map.String.set(bindings, "$parameters", ExpressionT.EParameters(parameters))
switch expression {
| ExpressionT.EValue(EvSymbol(aSymbol)) => {
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
| false =>
switch bindings->Belt.Map.String.get(aSymbol) {
| Some(boundExpression) => boundExpression->Ok
| None => RESymbolNotFound(aSymbol)->Error
switch bindings->Belt.Map.String.get(aSymbol) {
| Some(boundExpression) => boundExpression->Ok
| None => RESymbolNotFound(aSymbol)->Error
}
}
}
@ -54,14 +55,16 @@ let rec replaceSymbols = (expression: expression, bindings: ExpressionT.bindings
expr,
}) => {
let oldParameters = getParameters(bindings)
let newParameters = oldParameters->Belt.List.concat(parameters)
let newParameters = oldParameters->Js.Array2.concat(parameters)
let newBindings = putParameters(bindings, newParameters)
let rNewExpr = replaceSymbols(expr, newBindings)
rNewExpr -> Result.flatMap(newExpr => ExpressionT.EList(list{
ExpressionT.EValue(EvCall("$lambda")),
ExpressionT.EParameters(parameters),
newExpr
})->Ok)
rNewExpr->Result.flatMap(newExpr =>
ExpressionT.EList(list{
ExpressionT.EValue(EvCall("$lambda")),
ExpressionT.EParameters(parameters),
newExpr,
})->Ok
)
}
| ExpressionT.EList(list) => {
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 = (
list: list<expression>,
bindings: ExpressionT.bindings,
reduceExpression: reducerFn,
): result<expression, 'e> => {
let doBindStatement = (statement: expression, bindings: ExpressionT.bindings) => {
switch statement {
| ExpressionT.EList(list{

View File

@ -8,15 +8,19 @@ open Reducer_ErrorValue
type expression = T.expression
type expressionValue = ExpressionValue.expressionValue
type internalCode = ExpressionValue.internalCode
type t = expression
external castExpressionToInternalCode: expression => internalCode = "%identity"
external castInternalCodeToInternalCode: internalCode => expression = "%identity"
/*
Shows the expression as text of expression
*/
let rec toString = expression =>
switch expression {
| T.EBindings(_) => "$$bound"
| T.EParameters(params) => `(${Js.Array2.toString(params->Belt.List.toArray)})`
| T.EParameters(params) => `(${Js.Array2.toString(params)})`
| T.EList(aList) =>
`(${Belt.List.map(aList, aValue => toString(aValue))
->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> =>
switch expression {
// | T.EList(list{T.EValue(EvCall("$lambda")), T.EParameters(parameters), functionDefinition}) => {
// let lambda = T.ELambda(parameters, functionDefinition)
// lambda->Ok}
| T.EList(list{
T.EValue(EvCall("$lambda")),
T.EParameters(parameters),
functionDefinition,
}) => EvLambda(parameters, functionDefinition->castExpressionToInternalCode)->Ok
| T.EValue(value) => value->Ok
| T.EList(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)
}
| 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)
@ -142,7 +149,9 @@ let evalPartialUsingExternalBindings_ = (codeText: string, bindings: T.bindings)
Therefore all statments are assignments.
*/
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
| 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
| 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>

View File

@ -104,7 +104,7 @@ let rec fromNode = (mathJsNode: Parse.node): result<expression, errorValue> =>
let rValueExpression = fromNode(faNode["expr"])
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)
rLambda->Result.flatMap(lambda => {
passToFunction("$let", list{symbol, lambda}->Ok)

View File

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