向面向对象的程序员和技术人员解释函数式编程 [英] Explaining functional programming to object-oriented programmers and less technical people

查看:93
本文介绍了向面向对象的程序员和技术人员解释函数式编程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有什么好的例子可以用来解释函数式编程吗?

观众应该是没有编程经验的人,或者只有面向对象的人体验。

解决方案


观众可以是拥有
编程经验的人, p>

是否真的可以解释函数式编程,让OO或程序或任何编程范例很多编程经验?


或者只有
面向对象体验的人。

blockquote>

好吧,最好的例子可能是将已知的设计模式转换为其功能等效。让我们看一下将ints列表转换为字符串列表的典型示例:

  using System; 

命名空间Juliet
{
interface IConvertor< T,U>
{
U转换(T值);


class程序
{
static U [] Convert< T,U>(T [] input,IConvertor< T,U> convertor)
{
U [] res = new U [input.Length];
for(int i = 0; i< input.Length; i ++)
{
res [i] = convertor.Convert(input [i]);
}
return res;
}

class SquareInt:IConvertor< int,string>
{
public string Convert(int i)
{
return(i * i).ToString();
}
}

class ScaleInt:IConvertor< int,string>
{
readonly int Scale;

public Sc​​aleInt(int scale)
{
this.Scale = scale;


public string Convert(int i)
{
return(i * Scale).ToString();



static void Main(string [] args)
{
int [] nums = new int [] {1,2, 3,4,5,6,7,8,9,10};

string [] squared =转换< int,string>(nums,new SquareInt());
string [] tripled =转换< int,string>(nums,new ScaleInt(3));





$ b

其简单易读的对象面向对象,它甚至是通用的,因此适用于任意类型,那么问题是什么?首先,它的臃肿:我有一个接口定义和两个接口实现。如果我需要另一次转换呢?那么,我需要另一个接口实现 - 它可以很快失控。



当您考虑它时, IConvertor< T,U> ; class只是一个名为 Convert 的单个函数的包装 - 类实际上存在以帮助我们传递 Convert 到其他功能。如果你能理解这一点,那么你已经将函数背后的基本原理理解为一流的值 - 函数式编程就是将函数传递给其他函数,就像传递一个人,一个int或一个字符串一样。

人们通常更喜欢函数式编程,因为它可以帮助他们避免单一方法的接口和实现。而不是传递一个类,我们只是通过名字或匿名方式传递一个函数:

  using System; 

namespace Juliet
{
class Program
{
static U [] Convert< T,U>(T [] input,Func< T, U>转换器)
{
U [] res = new U [input.Length];
for(int i = 0; i< input.Length; i ++)
{
res [i] = convertor(input [i]);
}
return res;


静态字符串SquareInt(int i)
{
return(i * i).ToString();


static void Main(string [] args)
{
int [] nums = new int [] {1,2,3,4,5 ,6,7,8,9,10};

string [] squared =转换< int,string>(nums,SquareInt); //按名称传递函数
string [] tripled =转换< int,string>(nums,i =>(i * 3).ToString()); //或者匿名传递
}
}
}

好的,所以现在我们拥有完全相同的程序,只需要更少的代码行,它的可读性,以及它的功能非常明显。



现在有人可能会说这很整洁诀窍,但是我什么时候会用它? - 当你想要像这样传递函数时,有很多情况。它为您提供了更多的能力,以新颖的方式抽象您的程序控制流程。根据此处显示的示例进行调整,请考虑处理文件的类:

  class FileFunctions 
{
internal void SaveFile()
{
SaveFileDialog fileDialog = new SaveFileDialog();
fileDialog.Filter =文本文件(* .txt)| * .txt |所有文件(*。*)| *。*;
if(fileDialog.ShowDialog()== DialogResult.OK)
{
File.AppendAllText(fileDialog.FileName,MyDocument.Data);



内部无效WriteFile()
{
OpenFileDialog fileDialog = new OpenFileDialog();
fileDialog.Filter =文本文件(* .txt)| * .txt |所有文件(*。*)| *。*;
if(fileDialog.ShowDialog()== DialogResult.OK)
{
MyDocument.Data = File.ReadAllText(fileDialog.FileName);
}
}
}

Yuck。代码是重复的,但它在不同的类上执行操作并调用不同的方法。你将如何抽象出OO宇宙中的重复代码?在函数式编程中,它是微不足道的:

  class FileFunctions 
{
internal void ShowDialogThen(FileDialog dialog,Action< ; FileDialog> f)
{
dialog.Filter =文本文件(* .txt)| * .txt |所有文件(*。*)| *。*;
if(dialog.ShowDialog()== DialogResult.OK)
{
f(dialog);



internal void SaveFile()
{
ShowDialogThen(
new SaveFileDialog(),
dialog => ; File.AppendAllText(dialog.FileName,MyDocument.Data));


内部无效WriteFile()
{
ShowDialogThen(
new OpenFileDialog(),
dialog => {MyDocument.Data = File.ReadAllText(dialog.FileName);});
}
}

真棒。

What are some good examples that I can use to explain functional programming?

The audience would be people with little programming experience, or people who only have object-oriented experience.

解决方案

The audience would be people with little programming experience,

Is it really possible to explain functional programming, let along OO or procedural or any paradigm of programming to people without much programming experience?

or people who only have object-oriented experience.

Well probably the best examples would be converting known design patterns into their functional equivalent. Let's take the canonical example of converting a list of ints to a list of strings:

using System;

namespace Juliet
{
    interface IConvertor<T, U>
    {
        U Convert(T value);
    }

    class Program
    {
        static U[] Convert<T, U>(T[] input, IConvertor<T, U> convertor)
        {
            U[] res = new U[input.Length];
            for (int i = 0; i < input.Length; i++)
            {
                res[i] = convertor.Convert(input[i]);
            }
            return res;
        }

        class SquareInt : IConvertor<int, string>
        {
            public string Convert(int i)
            {
                return (i * i).ToString();
            }
        }

        class ScaleInt : IConvertor<int, string>
        {
            readonly int Scale;

            public ScaleInt(int scale)
            {
                this.Scale = scale;
            }

            public string Convert(int i)
            {
                return (i * Scale).ToString();
            }
        }

        static void Main(string[] args)
        {
            int[] nums = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

            string[] squared = Convert<int, string>(nums, new SquareInt());
            string[] tripled = Convert<int, string>(nums, new ScaleInt(3));
        }
    }
}

Its simple, readable, object-oriented, its even generic so it works for any arbitrary types, so what's the problem? For a start, its bloated: I have an interface definition and two interface implementations. What if I need another conversion? Well, I need another interface implementation -- it can get out of hand quickly.

When you think about it, the IConvertor<T, U> class is just a wrapper around a single function called Convert -- the class literally exists to help us pass Convert to other functions. If you can understand this much, then you already understand the basic principles behind functions as first-class values -- functional programming is all about passing functions to other functions in pretty much the same way you pass a person or an int or a string.

People usually prefer functional programming because it helps them avoid single-method interfaces and implementations. Instead of passing a class, we just pass a function by name or anonymously:

using System;

namespace Juliet
{
    class Program
    {
        static U[] Convert<T, U>(T[] input, Func<T, U> convertor)
        {
            U[] res = new U[input.Length];
            for (int i = 0; i < input.Length; i++)
            {
                res[i] = convertor(input[i]);
            }
            return res;
        }

        static string SquareInt(int i)
        {
            return (i * i).ToString();
        }

        static void Main(string[] args)
        {
            int[] nums = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

            string[] squared = Convert<int, string>(nums, SquareInt); // pass function by name
            string[] tripled = Convert<int, string>(nums, i => (i * 3).ToString()); // or pass anonymously
        }
    }
}

Alright, so now we have the exact same program in much fewer lines of code, its readable, and its very evident what its doing.

Now someone might say "that's a neat trick, but when would I use it" -- there are plenty of cases when you'd want to pass functions around like this. It gives you a lot more power to abstract your programs control flow in novel ways. Adapted from an example shown here, consider a class which handles files:

class FileFunctions
{
    internal void SaveFile()
    {
        SaveFileDialog fileDialog = new SaveFileDialog();
        fileDialog.Filter = "Text files (*.txt)|*.txt|All files (*.*)|*.*";
        if (fileDialog.ShowDialog() == DialogResult.OK)
        {
            File.AppendAllText(fileDialog.FileName, MyDocument.Data);
        }
    }

    internal void WriteFile()
    {
        OpenFileDialog fileDialog = new OpenFileDialog();
        fileDialog.Filter = "Text files (*.txt)|*.txt|All files (*.*)|*.*";
        if (fileDialog.ShowDialog() == DialogResult.OK)
        {
            MyDocument.Data = File.ReadAllText(fileDialog.FileName);
        }
    }
}

Yuck. The code is repetitious, but its performing operations on different classes and invoking different methods. How would you abstract away the duplicated code in the OO universe? In functional programing, it's trivial:

class FileFunctions
{
    internal void ShowDialogThen(FileDialog dialog, Action<FileDialog> f)
    {
        dialog.Filter = "Text files (*.txt)|*.txt|All files (*.*)|*.*";
        if (dialog.ShowDialog() == DialogResult.OK)
        {
            f(dialog);
        }
    }

    internal void SaveFile()
    {
        ShowDialogThen(
            new SaveFileDialog(),
            dialog => File.AppendAllText(dialog.FileName, MyDocument.Data));
    }

    internal void WriteFile()
    {
        ShowDialogThen(
            new OpenFileDialog(),
            dialog => { MyDocument.Data = File.ReadAllText(dialog.FileName); });
    }
}

Awesome.

这篇关于向面向对象的程序员和技术人员解释函数式编程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆