Sprache.Calc
Sprache.Calc copied to clipboard
Function with constants variables
Hi,
Is it possible to add constant vars when build a function? something like this:
var fn = calc.ParseFunction("a+b+c"); fn.Variables.Add("a",1); fn.Variables.Add("b",1); var compileFn = fn.Compile(); var result = compileFn(new Dictionary<string, double> { { "c", 2 } });
Or I need to interpolation constants variable before parse function? tks
Hello @mrxrsd, here you are:
using ParameterList = System.Collections.Generic.Dictionary<string, double>;
public Expression<Func<ParameterList, double>> ParseFunction(string text,
ParameterList constants)
{
var calc = new XtensibleCalculator();
var parsed = calc.ParseFunction(text).Compile();
return c => CallWithConstants(parsed, constants, c);
}
public double CallWithConstants(Func<ParameterList, double> function,
ParameterList constants, ParameterList variables)
{
var allVars = constants.Concat(variables).ToDictionary(p => p.Key, p => p.Value);
return function(allVars);
}
You can use the code like this:
using ParameterList = System.Collections.Generic.Dictionary<string, double>;
static void Main()
{
// parse function with constants
var constants = new ParameterList{{ "a", 1 }, { "b", 2 }};
var parsed = ParseFunction("a+b+c", constants);
var compiled = parsed.Compile();
// call compiled function with variables
var variables = new ParameterList{{ "c", 3 }};
compiled(variables);
}
It seems like it would be nice to have a more succinct way to write this, so that you can go from a simple calculator to a Von Neumann style computer with registers / saved state. The following doesn't seem possible in Sprache.Calc out of the box:
A = 1
B = 2
def Mul(a, b, c) = a * b * c
Mul(A, B, 3)
Otherwise, this library seems like a good start for a project I want to prove to myself I can write.
To be clear, I think some guidelines on the following might be worth brainstorming:
- Assignables (Immutable variables , lefthand values whose value is the result of a righthand expression)
- variadic arguments
- bonus: currying
It seems like it would be nice to have a more succinct way to write this, so that you can go from a simple calculator to a Von Neumann style computer with registers / saved state. The following doesn't seem possible in Sprache.Calc out of the box:
A = 1 B = 2 def Mul(a, b, c) = a * b * c Mul(A, B, 3)
Otherwise, this library seems like a good start for a project I want to prove to myself I can write.
To be clear, I think some guidelines on the following might be worth brainstorming:
- Assignables (Immutable variables , lefthand values whose value is the result of a righthand expression)
- variadic arguments
- bonus: currying
Hi,
Take a look at Jace .net.
https://github.com/pieterderycke/Jace/issues/43
@thiagottt Interesting; thanks. I started making progress towards using Sprache. Do you have any comparison between the two? It seems as though Jace.NET doesn't actually have a "local constant registry" as proposed in that issue, nor is it extensible like Sprache or Sprache.Calc is.
For some background, I am trying to replace a homebrewed alert system written using regular expressions. The language examples looks something like:
currentVal = someExcelFunction / someOtherExcelFunction
previousVal =
currentVal/previousVal-1
or
currentVal = someExcelFunction / someOtherExcelFunction
previousVal =
temp=currentVal/previousVal-1
=temp>.01
or
today = today()
updateDate = 41399
needUpdate = today > updateDate
currentVal = someExcelFunction / someOtherExcelFunction
previousVal =
temp=currentVal/previousVal-1
needAlert = temp< 1
or(needAlert, needUpdate)
Effectively, the last line in a "program" is always the return value. It may or may not start with an "=" sign.
I think that, I can't use Jace.NET, given the constraints of over >1000 tiny "programs" I would then need to port to Jace.NET.
It seems like it would be nice to have a more succinct way to write this, so that you can go from a simple calculator to a Von Neumann style computer with registers / saved state. The following doesn't seem possible in Sprache.Calc out of the box...
Keep in mind that Sprache.Calc doesn't have extensible AST. It uses LINQ expressions as the data model, so everything it generates should be assignable to Expression.
As far as I remember, LINQ expressions have support for statements since .NET 4.x, something like Expression.Block
, Expression.IfThen
, etc. So in theory we could build something like a tiny imperative language based on Sprache.Calc's approach. Not sure about local functions though :)
Hi @yallie I made decent progress prototyping a small language. Your project is a good template for thinking about things.
One piece of feedback on your CodeProject article: It is a little counter-intuitive to me to declare the Parser properties as virtual instead of public static
, especially reading your article on CodeProject. I think the one thing you didn't explain well was that XtensibleCalculator will derive from ScientificCalculator will derive from SimpleCalculator. If you read the code from the bottom of SimpleCalculator upwards, reading through ScientificCalculator and XtensibleCalculator is a lot easier. In fact, I found ScientificCalculator is mostly irrelevant for learning how to use Sprache.
Keep in mind that Sprache.Calc doesn't have extensible AST. It uses LINQ expressions as the data model, so everything it generates should be assignable to Expression.
Just thinking about this comment.
Why can't you "lift" such expressions?
In effect, massage the data model a bit before trying to convert everything to an expression tree. You can use erecruit.Expr to simplify some of your expression tree manipualtion.
Thanks for your feedback!
Sprache.Calc is my study on grammar inheritance, and everything is virtual so it can be overridden in derived classes. It's not a tutorial on writing Sprache parsers, it's more like an experiment on alternative ways of combining parsers.
Using built-in LINQ expression classes is just a way to keep my own code down to minimum. I definitely agree that custom AST classes would give much more flexibility in terms of manipulating the expressions, but it wasn't the goal :)
Yeah, you may want to Google for The Expression Problem / The Extensibility Problem.
Rather than phrasing the problem as "experiment on ways combining parsers", rephrase the problem as independently adding new operators and operands.
Note: I am good at the theory, but suck at the practice, so easier said than done:)
Rather than phrasing the problem as "experiment on ways combining parsers", rephrase the problem as independently adding new operators and operands.
I was interested in parsing different language dialects, like PostgreSQL and Oracle SQL for example, while reusing the core parser. Using OOP inheritance seemed to me like a natural tool for overriding different language parts.
That makes sense. It appears Nicholas has written a "sequel" to Sprache called Superpower, which is probably a better basis for very complex grammars like the ANSI SQL grammar and its vendor-specific extensions.
Did you ever write C#-based parsers for those languages? I'd be very interested to use them in FluentMigrator, even if they're slow and/or give bad error messages.
On Thu, Oct 17, 2019 at 5:00 PM Alexey Yakovlev [email protected] wrote:
Rather than phrasing the problem as "experiment on ways combining parsers", rephrase the problem as independently adding new operators and operands.
I was interested in parsing different language dialects, like PostgreSQL and Oracle SQL for example, while reusing the core parser. Using OOP inheritance seemed to me like a natural tool for overriding different language parts.
— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/yallie/Sprache.Calc/issues/2?email_source=notifications&email_token=AADNH7INK4D5BEOSM6WFH2LQPDG5ZA5CNFSM4HV6BPPKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEBRQGKQ#issuecomment-543359786, or unsubscribe https://github.com/notifications/unsubscribe-auth/AADNH7LTKPO4DEM4JMI6S7LQPDG5ZANCNFSM4HV6BPPA .
It appears Nicholas has written a "sequel" to Sprache called Superpower
Yes, it's not as easy to use as Sprache, but it probably has better error reporting.
Did you ever write C#-based parsers for those languages?
No I didn't, that was just an example, sorry :) Not sure if I ever used grammar inheritance in a real project.
The only grammar inheritance I like is basically the "pluggable parsing" concepts from Alex Warth and OMeta. The idea is that you use packrat expression grammar parsers to define the "first" part of your grammar and the "Rest" as a plug-in. You can the augment a grammar by incrementally refining what "Rest" Parser(s) do.
However, I am skeptical about its utility on really large scale systems like ANSI SQL, due to the number of "production rules" in the grammar.
On Thu, Oct 17, 2019 at 5:52 PM Alexey Yakovlev [email protected] wrote:
It appears Nicholas has written a "sequel" to Sprache called Superpower
Yes, it's not as easy to use as Sprache, but it probably has better error reporting.
Did you ever write C#-based parsers for those languages?
No I didn't, that was just an example, sorry :) Not sure if I ever used grammar inheritance in a real project.
— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/yallie/Sprache.Calc/issues/2?email_source=notifications&email_token=AADNH7I3TAHNT4H4H5CIKTDQPDNB7A5CNFSM4HV6BPPKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEBRUNRY#issuecomment-543377095, or unsubscribe https://github.com/notifications/unsubscribe-auth/AADNH7I5D7XFDLCX5JAKV6DQPDNB7ANCNFSM4HV6BPPA .