سؤال

أواجه مشكلة في الحصول على تمايز تلقائي للعمل بين C# و F#.

في C# لدي وظيفة تأخذ مضاعفة وتُرجع مزدوجًا ، قل:

private double Price(double yield)
{
    double price;

    price = 0;

    for (int index = 1; index <= _maturity * _frequency; index++)
    {
        price += (_coupon / _frequency) * _nominal / Math.Pow(1 + (yield / _frequency), index);
    }

    price += _nominal / Math.Pow(1 + (yield / _frequency), _maturity * _frequency);

    return price;
}

لقد اخترت هذه الوظيفة على وجه التحديد ، لأن Math.Pow باهظ للغاية ، ولا يسمح إلا بمقامات مزدوجة أو INT لمعلماتها.

أرغب في التمييز بين هذه الوظيفة باستخدام التمايز التلقائي. لقد كتبت الطريقة لهذا في F#:

type Diff(d : double, df : Lazy<Diff>) = class
    member x.d = d
    member x.df = df
    static member (+) (x : Diff, y : Diff) = 
        Diff(x.d + y.d, lazy (x.df.Value + y.df.Value)) 
    static member (-) (x : Diff, y : Diff) = 
        Diff(x.d - y.d, lazy (x.df.Value - y.df.Value))
    static member (*) (x : Diff, a : double) = 
        Diff(x.d * a, lazy (x.df.Value * a))
    static member (*) (x : Diff, y : Diff) = 
        Diff(x.d * y.d, lazy ((x.df.Value * y) + (y.df.Value * x)))
    override x.ToString() =
        x.d.ToString()
end

let rec dZero = Diff(0.0, lazy dZero)

let dConst x = Diff(x, lazy dZero)

let dId x = Diff(x, lazy dConst 1.0)

let Differentiate (x:Diff) = x.df.Value

// Example function
let f (x:Diff) = x*x*x;

// Example usage:
// (f (dId 5)).ToString = "125"
// (Differentiate (f (dId 5))).ToString = "75"
// (Differentiate (Differentate (f (dId 5)))).ToString = "30"

لسوء الحظ ، أحتاج إلى إطعام نوع Diff في وظيفة السعر (..) لإنتاج نوع Diff ، والذي يتم تغذيته بعد ذلك في وظيفتي (..) لإرجاع نوع آخر.

وظيفتي C# تعمل فقط على الزوجي (وأود أن تبقى على هذا النحو ، حيث يتم استخدامها في أماكن أخرى في برنامج C#).

الطريقة الوحيدة التي يمكنني التفكير بها في حل هذا هي كتابة كل وظيفة مرتين ، والتي من الواضح أنها مروعة مثل:

1) قد أكتب أيضًا نسخة متباينة في كل مرة 2) هذا ليس نموذجًا قابلاً للتوسيع للغاية

لذلك هل هناك أي طريقة يمكنني من خلالها الالتفاف على هذا ، أو ربما إجبار وظيفاتي المزدوجة في وظائف Diff (ويفضل في F#). من الناحية المثالية ، أود فقط رمي وظيفة (مزدوجة -> مزدوجة) في الحصول على diff.ToString ().

آسف إذا كان هذا غامضًا تمامًا أو مستحيلًا. سأجيب على أي أسئلة في التعليقات إذا كان هذا غير واضح.

آمل أن يكون هناك حل لهذا! شكرا مقدما،

آشلي

هل كانت مفيدة؟

المحلول

يمكنك إعادة اختراع فصول نوع Haskell:

interface Eq<T>
{
    bool Equal(T a, T b);
    bool NotEqual(T a, T b);
}

interface Num<T> : Eq<T>
{
    T Zero { get; }
    T Add(T a, T b);
    T Subtract(T a, T b);
    T Multiply(T a, T b);
    T Negate(T a);
}

sealed class Int : Num<int>
{
    public static readonly Int Instance = new Int();
    private Int() { }
    public bool Equal(int a, int b) { return a == b; }
    public bool NotEqual(int a, int b) { return a != b; }
    public int Zero { get { return 0; } }
    public int Add(int a, int b) { return a + b; }
    public int Subtract(int a, int b) { return a - b; }
    public int Multiply(int a, int b) { return a * b; }
    public int Negate(int a) { return -a; }
}

ثم يمكنك أن تفعل:

static T F<M, T>(M m, T x) where M : Num<T>
{
    return m.Multiply(x, m.Multiply(x, x));
}

static void Main(string[] args)
{
    Console.WriteLine(F(Int.Instance, 5));  // prints "125"
}

ثم مع:

class Diff
{
    public readonly double d;
    public readonly Lazy<Diff> df;

    public Diff(double d, Lazy<Diff> df)
    {
        this.d = d;
        this.df = df;
    }
}

class DiffClass : Floating<Diff>
{
    public static readonly DiffClass Instance = new DiffClass();
    private static readonly Diff zero = new Diff(0.0, new Lazy<Diff>(() => DiffClass.zero));
    private DiffClass() { }
    public Diff Zero { get { return zero; } }
    public Diff Add(Diff a, Diff b) { return new Diff(a.d + b.d, new Lazy<Diff>(() => Add(a.df.Value, b.df.Value))); }
    public Diff Subtract(Diff a, Diff b) { return new Diff(a.d - b.d, new Lazy<Diff>(() => Subtract(a.df.Value, b.df.Value))); }
    public Diff Multiply(Diff a, Diff b) { return new Diff(a.d * b.d, new Lazy<Diff>(() => Add(Multiply(a.df.Value, b), Multiply(b.df.Value, a)))); }
    ...
}

يمكنك القيام بالأمر:

static T Price<M, T>(M m, T _maturity, T _frequency, T _coupon, T _nominal, T yield) where M : Floating<T>
{
    T price;

    price = m.Zero;

    for (T index = m.Succ(m.Zero); m.Compare(index, m.Multiply(_maturity, _frequency)) <= 0; index = m.Succ(index))
    {
        price = m.Add(price, m.Divide(m.Multiply(m.Divide(_coupon, _frequency), _nominal), m.Power(m.Add(m.Succ(m.Zero), m.Divide(yield, _frequency)), index)));
    }

    price = m.Add(price, m.Divide(_nominal, m.Power(m.Add(m.Succ(m.Zero), m.Divide(yield, _frequency)), m.Multiply(_maturity, _frequency))));

    return price;
}

لكن هذا ليس جميلًا حقًا.

في الواقع ، فإنه يقرأ تقريبًا مثل الكود الذي ينشئ شجرة تعبير LINQ. ربما يمكنك استخدام مصدر الرمز تحول شجرة التعبير بدلاً من المشغل الزائد ليحقق التمايز التلقائي?

نصائح أخرى

لا توجد طريقة لاستخدام وظيفة C# الحالية ، ولا توجد طريقة سهلة لرفعها إلى وظيفة يمكن أن تعمل على أعضاء النوع Diff. بمجرد تجميع الوظيفة ، تكون غير شفافة والبنية الداخلية غير قابلة ؛ كل ما يمكنك فعله هو استدعاء الوظيفة بحجة مزدوجة والحصول على نتيجة مزدوجة. علاوة على ذلك ، الخاص بك Price تستخدم الطريقة العمليات التي لم تحددها حتى على Diff الفصل على أي حال ((\) و Pow).

لست متأكدًا مما إذا كان من المقبول لأغراضك ، ولكن أحد البديل المحتمل هو كتابة نسخة مضمنة عامة من Price الوظيفة في F#، والتي يمكن أن تعمل بعد ذلك على الزوجي أو DiffS (على افتراض أنك تضيف (\) و Pow العاملين).

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top