যে ফাংশনগুলি প্যারামিটার হিসাবে ফাংশন গ্রহণ করে সেগুলিও পরামিতি হিসাবে সেই ফাংশনগুলিতে পরামিতি গ্রহণ করে?


20

আমি প্রায়শই নিজেকে এই জাতীয় ফাংশনগুলি লেখার মতো দেখতে পাই কারণ এগুলি আমাকে সহজেই ডেটা অ্যাক্সেসকে উপহাস করার অনুমতি দেয় এবং এখনও কোনও স্বাক্ষর সরবরাহ করে যা কোন ডেটা অ্যাক্সেস করতে হবে তা নির্ধারণের জন্য পরামিতিগুলি গ্রহণ করে।

public static string GetFormattedRate(
        Func<string, RateType>> getRate,
        string rateKey)
{
    var rate = getRate(rateKey);
    var formattedRate = rate.DollarsPerMonth.ToString("C0");
    return formattedRate;
}

অথবা

public static string GetFormattedRate(
        Func<RateType, string> formatRate,
        Func<string, RateType>> getRate,
        string rateKey)
{
    var rate = getRate(rateKey);
    var formattedRate = formatRate(rate);
    return formattedRate;
}

তারপরে আমি এটিকে কিছু ব্যবহার করি:

using FormatterModule;

public static Main()
{
    var getRate = GetRateFunc(connectionStr);
    var formattedRate = GetFormattedRate(getRate, rateType);
    // or alternatively
    var formattedRate = GetFormattedRate(getRate, FormatterModule.FormatRate, rateKey);

    System.PrintLn(formattedRate);
}

এটি কি সাধারণ অনুশীলন? আমার মনে হচ্ছে আমার মতো আরও কিছু করা উচিত

public static string GetFormattedRate(
        Func<RateType> getRate())
{
    var rate = getRate();
    return rate.DollarsPerMonth.ToString("C0");
}

তবে এটি খুব ভালভাবে কাজ করছে বলে মনে হচ্ছে না কারণ প্রতি হারের ধরণের জন্য পদ্ধতিতে পাস করার জন্য আমাকে একটি নতুন ফাংশন তৈরি করতে হবে।

মাঝে মাঝে আমার মনে হয় আমার করা উচিত

public static string GetFormattedRate(RateType rate)
{
   return rate.DollarsPerMonth.ToString("C0");
}

তবে এটি কোনও আনয়ন এবং ফর্ম্যাট পুনরায় ব্যবহারের যোগ্যতা কেড়ে নেবে বলে মনে হচ্ছে। যখনই আমি আনতে এবং ফর্ম্যাট করতে চাই আমাকে দুটি লাইন লিখতে হবে, একটি আনতে হবে এবং একটিকে বিন্যাস করতে হবে।

ফাংশনাল প্রোগ্রামিং সম্পর্কে আমি কী মিস করছি? এটি কি এটি করার সঠিক উপায়, বা এর থেকে আরও ভাল প্যাটার্ন যা উভয়ই বজায় রাখা এবং ব্যবহার করা সহজ?


50
ডিআই ক্যান্সার এখনও পর্যন্ত ছড়িয়ে পড়েছে ...
ইডান আরে

16
এই কাঠামোটি কেন প্রথম স্থানে ব্যবহৃত হবে তা দেখার জন্য আমি সংগ্রাম করি। প্যারামিটার হিসাবে ফর্ম্যাট করার হারটি গ্রহণ করার পক্ষে অবশ্যই এটি আরও সুবিধাজনক (এবং পরিষ্কার ) GetFormattedRate(), কোনও প্যারামিটার হিসাবে ফর্ম্যাট করার হারকে ফিরিয়ে দেয় এমন কোনও ফাংশন গ্রহণ করার বিপরীতে?
অ্যারোথ

6
closuresআপনি যেখানে প্যারামিটারটি কোনও ফাংশনেই পাস করেন সেখান থেকে আরও ভাল উপায় ব্যবহার করা হচ্ছে , যার বিনিময়ে আপনাকে সেই নির্দিষ্ট পরামিতিটির উল্লেখ করে একটি ফাংশন দেয়। এই "কনফিগার করা" ফাংশনটি ফাংশনটির প্যারামিটার হিসাবে পাস হবে, যা এটি ব্যবহার করে।
টমাস জাঙ্ক

7
@ ইডানআরআই ডিআই ক্যান্সার?
জুলে

11
@ জুলস নির্ভরতা ইনজেকশন ক্যান্সার
বিড়াল

উত্তর:


39

আপনি যদি এটি যথেষ্ট পরিমাণে করেন তবে অবশেষে আপনি নিজেকে এই ফাংশনটি বারবার লিখে ফেলতে পারবেন:

public static Type3 CombineFunc1AndFunc2(
    Func<Type1, Type2> func1,
    Func<Type2, Type3>> func2,
    Type1 input)
{
    return func2(func1(input))
}

অভিনন্দন, আপনি ফাংশন রচনা আবিষ্কার করেছেন

এই জাতীয় মোড়কের কাজগুলি কোনও ধরণের ক্ষেত্রে বিশেষীকরণ করা হলে তেমন ব্যবহার হয় না। তবে, আপনি যদি কিছু ধরণের ভেরিয়েবল প্রবর্তন করেন এবং ইনপুট প্যারামিটার বাদ দেন, তবে আপনার গেটফর্ম্যাটরেট সংজ্ঞাটি দেখতে এরকম দেখাচ্ছে:

public static Func<A, C> Compose(
    Func<B, C> outer, Func<A, B>> inner)
{
    return (input) => outer(inner(input))
}

var GetFormattedRate = Compose(FormatRate, GetRate);
var formattedRate = GetFormattedRate(rateKey);

যেমনটি দাঁড়িয়েছে, আপনি যা করছেন তার উদ্দেশ্য খুব কম। এটি জেনেরিক নয়, সুতরাং আপনাকে সেই জায়গাটি সমস্ত জায়গায় নকল করতে হবে। এটি আপনার কোডকে অবিচ্ছিন্ন করে তোলে কারণ এখন আপনার কোডটিকে হাজার হাজার ক্ষুদ্র ফাংশন থেকে নিজের প্রয়োজন মতো যা কিছু প্রয়োজন তা একত্রিত করতে হবে। যদিও আপনার হৃদয় সঠিক জায়গায় রয়েছে: জিনিসগুলি একসাথে রাখার জন্য আপনাকে কেবল এই ধরণের জেনেরিক উচ্চতর অর্ডার ফাংশনগুলি ব্যবহার করতে অভ্যস্ত হওয়া প্রয়োজন । অথবা, একটি ভাল পুরানো ফ্যাশন ল্যামডা চালু করার জন্য ব্যবহার Func<A, B>এবং Aমধ্যে Func<B>

নিজেকে পুনরাবৃত্তি করবেন না।


16
নিজেকে পুনরাবৃত্তি করা এড়াতে কোডটি আরও খারাপ করে দিলে নিজেকে পুনরায় করুন। যেমন আপনি সবসময় পরিবর্তে এই দুটি লাইন লিখুন FormatRate(GetRate(rateKey))
ব্যবহারকারী 253751

6
@ মিমিবিস আমার ধারণা ধারণাটি হ'ল তিনি GetFormattedRateএখন থেকে সরাসরি ব্যবহার করতে সক্ষম হবেন ।
কার্লস

আমার মনে হয় আমি এখানে যা করার চেষ্টা করছি এটির আগেই আমি এই রচনাটির ফাংশনটি চেষ্টা করেছি তবে মনে হয় এটি খুব কমই ব্যবহার করব কারণ আমার ২ য় ফাংশনে প্রায়শই একাধিক প্যারামিটারের প্রয়োজন হয়। @
থোমাস

@ রশিঞ্জ এই ধরণের রচনাটি টিপিকাল এফপি ফাংশনে কাজ করে যা সর্বদা একটি যুক্তি থাকে (অতিরিক্ত যুক্তিগুলি সত্যই তাদের নিজস্ব কাজকর্ম হয়, এটির মতো চিন্তা করুন Func<Func<A, B>, C>); এর অর্থ হল যে আপনার কেবলমাত্র একটি রচনা ফাংশন প্রয়োজন যা কোনও ফাংশনের জন্য কাজ করে। যাইহোক, আপনি কেবল Func<rateKey, rateType>ক্লোজারগুলি ব্যবহার করে সি # ফাংশনগুলির সাথে যথেষ্ট পরিমাণে কাজ করতে পারেন - পাস করার পরিবর্তে , আপনার সত্যিকার অর্থেই প্রয়োজন হয় Func<rateType>এবং ফানকটি পাস করার সময় আপনি এটির মতো তৈরি করেন () => GetRate(rateKey)। মুল বক্তব্যটি হ'ল আপনি লক্ষ্যটি ফাংশনটি বিবেচনা করে না এমন যুক্তিগুলি প্রকাশ করবেন না।
লুয়ান

1
@ মিম্বিস হ্যাঁ, Composeযদি GetRateকোনও কারণে আপনাকে মৃত্যুদন্ড কার্যকর করতে বিলম্ব করতে হয় তবে ফাংশনটি সত্যই কার্যকর যখন যেমন আপনি কোনও ফাংশনটিতে যেতে চান Compose(FormatRate, GetRate)যা তার নিজস্ব পছন্দ অনুযায়ী একটি হার সরবরাহ করে, যেমন একটি প্রতিটি উপাদানকে এটি প্রয়োগ করতে তালিকা।
jpaugh

107

কোনও ফাংশন এবং তার পরামিতিগুলি পাস করার কোনও কারণ নেই, কেবলমাত্র সেই প্যারামিটারগুলির সাথে এটি কল করার জন্য। আসলে, আপনার ক্ষেত্রে আপনি একটি ফাংশন পাস কোন কারণ নেই এ সব । কলকারী পাশাপাশি কেবলমাত্র ফাংশনটি কল করে ফলাফলটি পাস করতে পারে।

এটি ব্যবহার করার পরিবর্তে - এটি সম্পর্কে ভাবেন:

var formattedRate = GetFormattedRate(getRate, rateType);

কেন কেবল ব্যবহার করবেন না:

var formattedRate = GetFormattedRate(getRate(rateType));

?

অপ্রয়োজনীয় কোড হ্রাস করার পাশাপাশি এটি সংযুক্তিকেও হ্রাস করে - আপনি কীভাবে হার আনেন তা পরিবর্তন করতে চান (বলুন, getRateএখন যদি দুটি যুক্তি প্রয়োজন হয়) আপনাকে পরিবর্তন করতে হবে না GetFormattedRate

তেমনি, লেখার GetFormattedRate(formatRate, getRate, rateKey)পরিবর্তে লেখার কোনও কারণ নেই formatRate(getRate(rateKey))

জিনিসগুলিকে অত্যধিক জটিল করবেন না।


3
এই ক্ষেত্রে আপনি সঠিক। তবে যদি অভ্যন্তরীণ ফাংশনটি একাধিকবার ডাকা হয়, একটি লুপে বা মানচিত্রের ফাংশনে বলুন, তবে আর্গুমেন্টে পাস করার ক্ষমতাটি কার্যকর হবে। অথবা @ জ্যাক উত্তরে প্রস্তাবিত হিসাবে কার্যকরী রচনা / কারিঙ ব্যবহার করুন।
ব্যবহারকারী949300

15
@ ব্যবহারকারী949300 হতে পারে, তবে এটি অপির ব্যবহারের ক্ষেত্রে নয় (এবং যদি এটি হয় তবে সম্ভবত এটি formatRateযে ফর্ম্যাট করা উচিত তার হারের তুলনায় ম্যাপ করা উচিত)।
jonrsharpe

4
@ ব্যবহারকারী949300 কেবলমাত্র যদি আপনার ভাষা বন্ধগুলি সমর্থন করে না বা লামদাস যখন টাইপ করার মতো ঝামেলা হয়ে থাকে
বার্গি

4
নোট যে অন্য ফাংশন একটি ফাংশন এবং তার পরামিতি ক্ষণস্থায়ী একটি হল সম্পূর্ণই বৈধ উপায় অলস শব্দার্থবিদ্যা ছাড়া একটি ভাষায় বিলম্ব মূল্যায়ন en.wikipedia.org/wiki/Thunk
জ্যারেড স্মিথ

4
@ জ্যারেডস্মিথ ফাংশনটি পাস করছে, হ্যাঁ, এর পরামিতিগুলি পার করছে, কেবলমাত্র যদি আপনার ভাষা বন্ধ করতে সমর্থন করে না।
ব্যবহারকারী 253751

15

আপনার যদি একেবারে কোনও ফাংশনটি ফাংশনে পাস করার প্রয়োজন হয় কারণ এটি কিছু অতিরিক্ত যুক্তি পাস করে বা এটিকে একটি লুপে কল করে তবে আপনি পরিবর্তে ল্যাম্বদা পাস করতে পারবেন:

public static string GetFormattedRate(
        Func<string> getRate)
{
    var rate = getRate();
    var formattedRate = rate.DollarsPerMonth.ToString("C0");
    return formattedRate;
}

var formattedRate = GetFormattedRate(()=>getRate(rateKey));

ল্যাম্বদা আর্গুমেন্টগুলি আবদ্ধ করবে যে ফাংশনটি জানেন না এবং লুকিয়ে রাখেন যে তারা উপস্থিত রয়েছে।


-1

এটি কি আপনি চান না?

class RateFormatter
{
    public abstract RateType GetRate(string rateKey);

    public abstract string FormatRate(RateType rate);

    public string GetFormattedRate(string rateKey)
    {
        var rate = GetRate(rateKey);
        var formattedRate = FormatRate(rate);
        return formattedRate;
    }
}

এবং তারপরে এটিকে কল করুন:

static class Program
{
    public static void Main()
    {
        var rateFormatter = new StandardRateFormatter(connectionStr);
        var formattedRate = rateFormatter.GetFormattedRate(rateKey);

        System.PrintLn(formattedRate);
    }
}

আপনি যদি এমন একটি পদ্ধতি চান যা কোনও اعتراض-ভিত্তিক ভাষায় যেমন সি # তে একাধিকভাবে আচরণ করতে পারে, তবে এটি করার সাধারণ উপায়টি হল পদ্ধতিটি একটি বিমূর্ত পদ্ধতিকে কল করা। এটি অন্যভাবে করার জন্য আপনার যদি নির্দিষ্ট কারণ না থাকে তবে আপনার এটি করা উচিত।

এটি কি কোনও ভাল সমাধানের মতো দেখায়, বা আপনি কী ভাবেন সেগুলি কি ডাউন?


1
আপনার উত্তরে বেশ কয়েকটি দুশ্চিন্তা জিনিস রয়েছে (কেন এটি ফর্ম্যাটরটিও রেট পাচ্ছে, এটি যদি কেবল একটি ফর্ম্যাটর থাকে? আপনি GetFormattedRateপদ্ধতিটি সরিয়ে ফেলতে পারেন এবং কেবল কল করতে পারেন IRateFormatter.FormatRate(rate))। তবে প্রাথমিক ধারণাটি সঠিক, এবং আমি মনে করি যে ওপিকেও যদি একাধিক ফর্ম্যাটিং পদ্ধতির প্রয়োজন হয় তবে কোড কোড পলিমারফিক্যালি প্রয়োগ করা উচিত।
বিজিআর ওয়ার্কার
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.