在C#中确认格林斯普的第十定律

时间:2010-02-05 16:56:55

标签: c# expression currying

我正在尝试在C#中实现一个允许我制作任意数学表达式的基础结构。例如,我希望能够采用像

这样的表达式

asin(sqrt(z - sin(x + y)^ 2))

并将其转换为一个对象,允许我根据x,y和z来评估它,得到导数,并可能在其上做某种符号代数。在C#中人们对这个好模型的看法是什么?

我有自己的想法,我担心它会走向建筑航天,所以我想确保不是这样。

基本上,像sin,+,sqrt等函数的类基于基类:

Function

Function<TOut> : Function
    TOut Value

Function<Tin, TOut> : Function
    TOut Evaluate(TIn value)
    Function Derivative
    Function<TOut, TIn> INverse

Function<TInA, TInB, TOut> : Function
    TOut Evaluate(TInA valueA, TInB valueB)
    Function PartialDerivativeA
    Function PartialDerivativeB
到目前为止,这么简单。诀窍是如何组合功能。在这里,我相信我想要一个像currying方法的东西,这样我就可以评估单个参数的功能,并保留其他参数。所以我想有一个像这样的工厂类:

Function<TInA, TInB, TOut> -> 
           Function<TInA, Function<TInB, TOut>>

(Function<TInA, TInB, TOut>, Function<TInX, TInA>, null) -> 
           Function<TInX, Function<TInB, TOut>>

(Function<TInA, TInB, TOut>, Function<TInA>, Function<TInX, TInY, TInB>) -> 
           Function<TInX, Function<TInY, TInB>>

等等。我主要担心的是泛型类型可能会使系统无法使用(如果要求用户知道要评估的完整泛型类型),并且我可能无法从输入参数构造所有泛型类型。 / p>

感谢您的投入!

4 个答案:

答案 0 :(得分:1)

请注意,可以使用C#编译器来计算表达式。

通过在运行时编译C#代码来评估数学表达式 http://www.codeproject.com/KB/recipes/matheval.aspx

答案 1 :(得分:0)

我不完全确定curry是什么,但解析表达式的常用方法是构建abstract syntax tree
从中可以很难评估表达式,找到衍生物,或者你想做什么。


[编辑] 我担心你的评论毫无意义。从它的声音中,你想要解析一个表达式并构建一个AST,你可以用它做任何你想做的事情。是的,您将为每种类型的节点构建类;像这样的东西

public class PlusNode : BinaryNode
{
    public PlusNode(Node left, Node right) { base(left, right); }
    public virtual double Evaluate() { return Left.Evaluate() + Right.Evaluate(); }
    public virtual Node BuildDerivative()
    {
        return new PlusNode(Left.BuildDerivative(), Right.BuildDerivative());
    }
}

public class SinNode : UnaryNode
{
    public SinNode(Node child) { base(child); }
    public virtual double Evaluate() { return Math.Sin(Child.Evaluate()); }
    public virtual Node BuildDerivative()
    {
        return new MultiplyNode(new CosNode(Child.Clone()), Child.BuildDerivative()); //chain rule
    }
}

答案 2 :(得分:0)

使用Expression Trees怎么样?请注意,在链接页面上,甚至还有一个用于构建curried函数的示例(从通用的“less than”运算符和固定常量构建“少于5个”函数)

答案 3 :(得分:0)

有趣的是,几个月前我在D中实际上做过这个并没有收到特别有趣的内容。我的方法是使用模板化表达式树类。我有一个二进制类模板,可以使用+*等实例化,这是一个可以用sinexp等实例化的一元类。衍生工具由主要是递归应用链和产品规则。例如:

class Binary(alias fun) : MathExpression {
    MathExpression left, right;

    MathExpression derivative() {
        static if(is(fun == add)) {
            return left.derivative + right.derivative;
        } else static if(is(fun == mul)) {
            return left.derivative * right + right.derivative * left;
        }
    }

    real opCall(real x) {
        return fun(left(x), right(x));
    }
}


class Unary(alias fun) : MathExpression {
    MathExpression inner;

    MathExpression derivative() {
        static if(is(fun == sin)) {
            return Unary!(sin)(inner.derivative);
        }
    }

    real opCall(real x) {
        return fun(inner(x));
    }
}

class Constant : MathExpression {

    real val;

    real opCall(real x) {
        return val;
    }

    real derivative() {
        return new Constant(0);
    }
}