Detailed example code for C # functional programming

Source: Internet
Author: User
In the case of functional programming, it is important to think of a highly flexible and dynamic lisp,haskell such as the ancient functional language, and to say that ruby,javascript,f# is also a popular language for functional programming. However, since. NET supports lambda expressions, C #, as an instruction-oriented programming language, is no less in functional programming. In the process of writing code in C #, we intentionally and unintentionally use higher-order functions, combinatorial functions, pure function caches, and so on, even the idea of the expression tree comes from functional programming. So then we summarize the usual functional programming scenarios, which will help us to apply these techniques flexibly in the process of programming, expand our design ideas and improve the quality of our code.

First, higher order function

Higher-order functions are popular: functions are used as parameters in a function, and such functions are called higher-order functions. According to this definition, the large number of LINQ expressions used in. NET, Where,select,selectmany,first, and so on are high-level functions, so when do we use this design when we write our own code?

Example: Design a function for calculating the cost of a property, Var fee=square*price, and the area (square) is calculated differently depending on the nature of the property. For residential, commercial housing and so on need to multiply the different coefficients, according to this demand we try to design the following function:

Residential area of civil housing:

Public func<int,int,decimal> Squareforcivil () {    return (width,hight) =>width*hight;}

Commercial House size:

public func<int, int, decimal> squareforbusiness () {    return (width, hight) = width * HIGHT*1.2M;}

These functions all have a common signature: func<int,int,decimal> So we can use this function signature to design a function that calculates the cost of a property:

Public decimal propertyfee (decimal price,int width,int hight, func<int, int, decimal> square) {    return price* Square (width, hight);}

Is it easy to write a test to see

[test]public void Should_calculate_propertyfee_for_two_area () {    //arrange    var calculator = new Propertyfeecalculator ();    Act    var feeforbusiness= calculator. Propertyfee (2m,2, 2, Calculator. Squareforbusiness ());    var feeforcivil = Calculator. Propertyfee (1m, 2, 2, Calculator. Squareforcivil ());    Assert    feeforbusiness.should (). Be (9.6m);    Feeforcivil.should (). Be (4m);}

Second, the lazy evaluation

C # uses a rigorous evaluation strategy in its execution, so-called rigorous evaluation refers to the evaluation of parameters before they are passed to the function. Is this explanation still a little unclear? Let's take a look at a scenario where a task needs to be performed, requires that the current memory usage is less than 80%, and the result of the previous step is <100 to meet this condition in order to perform the task.

We can quickly write C # code that meets this requirement:

Public double memoryutilization () {     //calculates current memory utilization     var pcinfo = new ComputerInfo ();     var usedmem = pcinfo.totalphysicalmemory-pcinfo.availablephysicalmemory;      Return (double) (Usedmem/convert.todecimal (pcinfo.totalphysicalmemory)); } public  int bigcalculatationforfirststep () {     ///first-step operation     System.Threading.Thread.Sleep ( Timespan.fromseconds (2));     Console.WriteLine ("Big Calulation");     Firststepexecuted = true;     return 10; } public  void NextStep (double memoryutilization,int firststepdistance) {//Next operation     if (memoryutilization< 0.8&&firststepdistance<100)     {         Console.WriteLine ("Next Step");}     }

The calculation of the memory usage and the first step (function Bigcalculatationforfirststep) is required to execute the NEXTSTEP, as shown in the code, the first operation is a time-consuming operation, but due to the strict evaluation strategy of C #, for the statement if ( MEMORYUTILIZATION<0.8&&FIRSTSTEPDISTANCE<100), even if the memory usage is already greater than 80%, the first operation has to be performed, obviously, if memory usage is greater than 80%, Value Firststepdistance is no longer important, it can be done without calculation.

So lazy evaluation means that an expression or part of an expression is evaluated only when it really needs its results. We try to rewrite this requirement with higher-order functions:

public void Nextstepwithorderfunction (func<double> memoryutilization,func<int> firstStep) {    if ( Memoryutilization () < 0.8 && Firststep () < [+]    {        Console.WriteLine ("Next Step");}    }

The code is simple, which is to replace the function value with a function expression if (memoryutilization () < 0.8: This is not enough, the function behind it will not execute. Microsoft has added the Lazy<t> class to the. net4.0 version, and you can use this mechanism in scenarios where this is required.

Three, function curry (Curry)

Curry is also referred to as local apply. Definition: A technique that transforms a function that accepts multiple parameters into a function that takes a single parameter (the first parameter of the original function) and returns a new function that takes the remaining parameters and returns the result, PS: Why does the official explanation go so round?

It's hard to see how this is going to happen, so let's start with the curry principle:

Write a function that adds two numbers:

public func<int, int, int> addtwonumber () {    return (x, y) = = x + y;}

OK, how do I use this function?

var result= _curringreasoning.addtwonumber ();

1+2=3, the call is simple. To upgrade the requirements, we need a function that requires the input of a parameter (number) to calculate the result of the parameter (number) of the + + input. Estimated someone to say, this needs the above code can be fully implemented Ah, the first parameter you passed 10 is not finished, OK, if you think so, I also helpless. Others may say, and then write an overload, as long as a parameter can be, the reality is not allowed, we call other people to provide the API, cannot add overloading. It is not a common scenario to see local application scenarios, so the best design is to fit the right technology in the right scenario, and we'll look at the implementation of local implementations:

Public Func<int, Func<int, int>> addtwonumbercurrying () {    func<int, func<int, int>> addcurrying = x = y + = x + y;    return addcurrying;}

The expression x = y = x + y Gets the function signature for Func<int, Func<int, int>> This function signature is very clear, receive an int type parameter, get a func<int,int> Type of function. At this point if we call again:

Actvar Curringresult = curringreasoning.addtwonumbercurrying (), var result = Curringresult (2); Assertresult.should (). Be (12);

This sentence: var curringresult = curringreasoning.addtwonumbercurrying () (10); The generated function is to receive only one parameter (number), and the 10+number function can be computed.

For the same reason, the three-number function:

Public func<int,int,int,int> Addthreenumber () {    return (x, y, Z) = + x + y + z;}

Locally applied version:

Public func<int,func<int,func<int,int>>> addthreenumbercurrying () {    func<int, Func<int , Func<int, int>>> addcurring = x = y = z + = x + y + z;    return addcurring;}

Call Procedure:

[test]public void Three_number_add_test () {    //arrange    var curringreasoning = new curryingreasoning ();     Act    var result1 = Curringreasoning.addthreenumber () (1, 2, 3);    var curringresult = curringreasoning.addthreenumbercurrying () (1);    var curringResult2 = Curringresult (2);    var result2 = CURRINGRESULT2 (3);        Assert    RESULT1. Should (). Be (6);    Result2. Should (). Be (6);}

When the function parameters are more, manual local application is more and more difficult to write, we can use the extension method to automatically apply:

public static func<t1, Func<t2, tresult>> curry<t1, T2, tresult> (this func<t1, T2, tresult> Func) {    return x = y = = func (x, y);} public static func<t1, Func<t2, Func<t3, tresult>>> curry<t1, T2, T3, tresult> (this func<t1, T 2, t3,tresult> func) {    return x = y = Z=>func (x, y,z);}

Similarly, the,action<> signature function can also be applied automatically.

With these extension methods, it's easier to use local application.

[test]public void Should_auto_curry_two_number_add_function () {    //arrange    var add = _ Curringreasoning.addtwonumber ();    var addcurrying = Add. Curry ();     Act    var result = addcurrying (1) (2);     Assert    result. Should (). Be (3);}

Well, in this case, StackOverflow has several articles about the scenes and definitions used by currying, which you can continue to understand.

Functional programming also has some important ideas, such as: pure function of the cache, the pure function refers to the function of the call is not affected by the outside world, the same parameter call the resulting value is always the same. The tail recursion, the list, the code is the data (expression tree in. net), some applications, the combination of functions, some of which I am still learning, some are still thinking about their best use of the scene, so no longer summed up, if one day to grasp the idea will be added.

Iv. Design Cases

Finally I want to design a scene, the high-order functions, lambda expressions, generic methods together, I design such an example is because there are many frameworks, open source projects have a similar way of writing, it is because of a combination of technology and ideas, there is very expressive and very elegant code.

Requirements: Design a word finder, which can find out whether some fields of an incoming model contain a word, because different model has different fields, so the lookup needs to be configured, and you can take advantage of the smart hints of vs.

This feature actually has two methods:

Private ReadOnly list<func<string, bool>> _conditions;  Public wordfinder<tmodel> find<tproperty> (func<tmodel,tproperty> expression) {    func< String, bool> searchcondition = Word = = Expression (_model). ToString (). Split ('). Contains (word);    _conditions. ADD (searchcondition);    return this;} public bool Execute (string wordList) {    return _conditions. Any (x=>x (wordList));}

Use:

[test]public void Should_find_a_word () {    //arrange    var article = new article ()    {        title = "This is a title" ,        content = "This is the content",        Comment = "This was Comment",        Author = "This is Author"    };     Act    var result = finder.for (article)        . Find (x = x.title)        . Find (x = x.content)        . Find (x = x.comment)        . Find (x = x.author)        . Execute ("content");     Assert    result. Should (). Be (true);

The case itself is not practical, but you can see that it is a comprehensive application of various technologies to design a very semantic API, if the function parameter is changed to expression<func<tmodel,tproperty>> type, We can also read information such as the specific property name.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.