Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/308.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 确认格林斯潘';第十定律#_C#_Expression_Currying - Fatal编程技术网

C# 确认格林斯潘';第十定律#

C# 确认格林斯潘';第十定律#,c#,expression,currying,C#,Expression,Currying,我正在尝试用C#实现一个基础设施,它允许我生成任意的数学表达式。例如,我希望能够接受这样的表达式 asin(sqrt(z-sin(x+y)^2)) 把它变成一个物体,让我可以用x,y,z来计算它,得到导数,还可能对它做一些符号代数。人们对C#中的好模式有什么看法 我有自己的观点,我担心这将进入建筑航天领域,所以我想确保情况并非如此 基本上,sin、+、sqrt等函数都有基于基类的类: Function Function<TOut> : Function TOut Value

我正在尝试用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
函数
功能:功能
兜售价值
功能:功能
TOut评估(锡值)
函数导数
函数逆
功能:功能
TOut评估(TInA valueA、TInB valueB)
部分导数函数
函数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>>
函数->
作用
(函数,函数,null)->
作用
(功能,功能,功能)->
作用
等等。我主要担心的是泛型类型可能会使系统不可用(如果用户需要知道完整的泛型类型才能进行评估),并且我可能无法从输入参数构造所有泛型类型


谢谢你的意见

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

通过在运行时编译C#代码来计算数学表达式

我不完全确定什么是咖喱,但解析表达式的常用方法是构建一个。
从这一点上,应该不难计算表达式,找到导数,或者你想做的任何事情


[编辑]恐怕你的评论毫无意义。从它的发音来看,您想要解析一个表达式并构建一个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
    }
}

那使用什么呢?请注意,在链接页面上,甚至有一个构建某种curry函数的示例(从通用的“小于”运算符和固定常量构建“小于5”函数)

有趣的是,我几个月前在D中确实做了这件事,但并没有得到特别的关注。我的方法是使用模板化的表达式树类。我有一个二进制类模板,可以用
+
*
等来实例化,一元类可以用
sin
exp
等来实例化。派生类主要通过递归应用链和乘积规则来工作。例如:

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);
    }
}

对我来说,编译后的表达式就像委托一样不透明。我需要对这些对象做一些元操作,比如显示底层表达式。Anders和他的团队打算打开C#编译器,允许它作为一种服务使用(这将提供更大的灵活性,因为当前的编译器本质上是一个黑匣子),但这种能力还不存在。对,问题是,基本上,如何表示AST的自由参数,灵活性和类型安全性之间的正确平衡是什么?@Reveazure:如果你说的“自由参数”是指“变量”,那么你可以随心所欲;可以存储字符串,也可以存储为具有名称和值的对象。这其实并不重要,只要你在树中找到一个,你就可以识别它(注意,所有的叶子都是数字或变量,反之亦然)。如果你对这个主题感兴趣的话,下面是我关于currying是什么的文章:到目前为止,所有回答的问题基本上是函数提供的功能,我需要类,而不是函数参数,我需要“curry”类类型参数。是的,但假设我有一个类似((/x(^y 2))的表达式。^是二进制运算符,但是(^y 2)只有一个参数。那么(^y 2)的类型应该是什么呢?我想你能看到我要去哪里。我坦率地承认我有点困惑。这就是为什么我要问。这里的问题是我真正想要的是一个类树,它有像ToString这样的东西,让我得到它们的导数。此外,我并不需要编译表达式或从C#代码动态生成表达式的能力。我建议使用Matlab或Mathematica之类的工具,而不是尝试重新发明轮子。为什么你认为你需要用泛型来实现这一点?使用普通的类层次结构似乎是完全可行的(而且稍微简单一点)。