F#之旅3 - F# PK C#:简单的求和

原文链接:https://swlaschin.gitbooks.io/fsharpforfunandprofit/content/posts/fvsc-sum-of-squares.html

Comparing F# with C#: A simple sum
F# PK C#:简单的求和

To see what some real F# code looks like, let‘s start with a simple problem: "sum the squares from 1 to N".
We‘ll compare an F# implementation with a C# implementation. First, the F# code:
// define the square function
let square x = x * x

// define the sumOfSquares function
let sumOfSquares n =
[1..n] |> List.map square |> List.sum

// try it
sumOfSquares 100

我们以“计算从1到n的平方的和”这个简单问题开始,来看一下实际的F#代码。
我们将比较F#实现和C#实现的不同。首先,F#如下:
// 定义一个求平方的函数
let square x = x * x
// 定义一个求平方和的函数
let sumOfSquares n =
[1..n] |> List.map square |> List.sum
// 试一下效果
sumOfSquares 100

The mysterious looking |> is called the pipe operator. It just pipes the output of one expression into the input of the next. So the code for sumOfSquares reads as:
1、Create a list of 1 to n (square brackets construct a list).
2、Pipe the list into the library function called List.map, transforming the input list into an output list using the "square" function we just defined.
3、Pipe the resulting list of squares into the library function called List.sum. Can you guess what it does?
4、There is no explicit "return" statement. The output of List.sum is the overall result of the function.

|>,这个神秘的东东叫做管道操作符。它做的就是把一个表达式的输出传到另一个表达式的输入。所以,这些代码的意思是:
1、创建一个从1到n的列表(中括号来创建列表)。
2、将列表传(流)到叫做List.map的库函数,使用我们刚刚定义的“平方”函数来进行从输入到输出的转换。
3、将得到的平方值的列表传到叫做List.sum的库函数。你猜下它做了啥?
4、这里没有显式的“返回”说明。List.sum的输出就是这个函数的全部结果输出了。

Next, here‘s a C# implementation using the classic (non-functional) style of a C-based language. (A more functional version using LINQ is discussed later.)
接下来,是一份C#的实现,用的是传统的类C语言的风格。(后面会讨论用LINQ实现的更函数式的版本)

public static class SumOfSquaresHelper
{
public static int Square(int i)
{
return i * i;
}

public static int SumOfSquares(int n)
{
int sum = 0;
for (int i = 1; i <= n; i++)
{
sum += Square(i);
}
return sum;
}
}

What are the differences?
The F# code is more compact
The F# code didn‘t have any type declarations
F# can be developed interactively
Let‘s take each of these in turn.
有什么区别?
F#的代码更简洁
F#的代码没有任何类型声明
F#能交互式的开发
我们来逐条的理解。

Less code
The most obvious difference is that there is a lot more C# code. 13 C# lines compared with 3 F# lines (ignoring comments). The C# code has lots of "noise", things like curly braces, semicolons, etc. And in C# the functions cannot stand alone, but need to be added to some class ("SumOfSquaresHelper"). F# uses whitespace instead of parentheses, needs no line terminator, and the functions can stand alone.
In F# it is common for entire functions to be written on one line, as the "square" function is. The sumOfSquares function could also have been written on one line. In C# this is normally frowned upon as bad practice.
When a function does have multiple lines, F# uses indentation to indicate a block of code, which eliminates the need for braces. (If you have ever used Python, this is the same idea). So the sumOfSquares function could also have been written this way:
let sumOfSquares n =
[1..n]
|> List.map square
|> List.sum
The only drawback is that you have to indent your code carefully. Personally, I think it is worth the trade-off.
更少的代码
很明显,最大的区别是C#的代码要多得多。13行C#代码对应3行F#代码(不包含注释)。C#的代码有很多“杂音”,比如大括号、分号等等。并且C#的函数不能单独的存在,必须放在一个类里面。F#用空格代替了括号的左右,不需要行尾终结符,并且函数可以独立存在。
在F#里,经常可以像“square”函数一样,把整个函数写成一行。“sumOfSquares”函数也可以写成一行。在F#里,这样做就是不被认可的坏习惯了。
当一个函数有多行时,F#用缩进来凸出一个代码块,而不需要额外的大括号。(如果你用过python,会发现这点和python一样)。因此,“sumOfSquares”函数也可以写成这样:
let sumOfSquares n =
[1..n]
|> List.map square
|> List.sum
唯一的缺点是需要小心你的缩进。个人认为,这样也挺好的。

No type declarations
The next difference is that the C# code has to explicitly declare all the types used. For example, the int i parameter and int SumOfSquares return type. Yes, C# does allow you to use the "var" keyword in many places, but not for parameters and return types of functions.
In the F# code we didn‘t declare any types at all. This is an important point: F# looks like an untyped language, but it is actually just as type-safe as C#, in fact, even more so! F# uses a technique called "type inference" to infer the types you are using from their context. It works amazingly very well most of the time, and reduces the code complexity immensely.
In this case, the type inference algorithm notes that we started with a list of integers. That in turn implies that the square function and the sum function must be taking ints as well, and that the final value must be an int. You can see what the inferred types are by looking at the result of the compilation in the interactive window. You‘ll see something like:
val square : int -> int
which means that the "square" function takes an int and returns an int.
没有类型声明
第二个区别,是C#代码显示的声明了所有用到的类型。例如,参数i是int类型,函数SumOfSquares的返回类型也是int。是的,C#也允许在很多地方用“var”关键字类自动推导类型,但是函数参数和函数返回值用不了。
在F#代码里,我们不需要声明所有类型。有一点很重要:F#看起来像是无类型(弱类型)语言,但它确实和C#一样是类型安全的,千真万确!F#用了一种叫做“类型推导”的技术来从上下文推断出类型。大部分时候它工作得出奇的好,极大的减少了代码的复杂性。
在这里,类型推导算法记录到:从一个整型列表开始。那么,又意味着square函数和sum函数必须能接受整型数值作为参数,并且得到的结果也要是整型。如果在交互窗口写代码,你可以直接在窗口里看到推导出来的类型。你会看到类似这样的东西:
val square : int -> int
意思是square函数接受一个整型,并且返回一个整型。

If the original list had used floats instead, the type inference system would have deduced that the square function used floats instead. Try it and see:
// define the square function
let squareF x = x * x

// define the sumOfSquares function
let sumOfSquaresF n =
[1.0 .. n] |> List.map squareF |> List.sum // "1.0" is a float

sumOfSquaresF 100.0
The type checking is very strict! If you try using a list of floats ([1.0..n]) in the original sumOfSquares example, or a list of ints ([1 ..n]) in the sumOfSquaresF example, you will get a type error from the compiler.
如果初始列表里用浮点型代替整型,类型推导系统也能推导出:square用浮点型输入输出。
...
类型检查是非常严格的!如果你尝试输入浮点型列表到之前的sumOfSquares,或者将整型的列表输入到sumOfSquaresF,编译器都会给你报类型错误。

Interactive development
Finally, F# has an interactive window where you can test the code immediately and play around with it. In C# there is no easy way to do this.
For example, I can write my square function and immediately test it:
// define the square function
let square x = x * x

// test
let s2 = square 2
let s3 = square 3
let s4 = square 4
When I am satisfied that it works, I can move on to the next bit of code.
This kind of interactivity encourages an incremental approach to coding that can become addictive!
Furthermore, many people claim that designing code interactively enforces good design practices such as decoupling and explicit dependencies, and therefore, code that is suitable for interactive evaluation will also be code that is easy to test. Conversely, code that cannot be tested interactively will probably be hard to test as well.
交互式开发
最后一点,F#还有一个交互式窗口,可以用来直接输入代码经常测试。C#不容易做到这点。
举个例子,我可以直接写一个square函数并且测试它:
...
当我觉得这个函数让我满意时,我再把它移到别的代码里用。
这样的交互式,让我们可以用增量的方式来写代码,让人上瘾!(我是没感觉的)
此外,很多人声称,把代码设计成可以交互式执行,是一个良好的设计实践,能解耦和明确依赖关系,因此,适合于交互式评审的代码也将是容易测试的代码。反之,无法进行交互测试的代码也会很难测试。

The C# code revisited
My original example was written using "old-style" C#. C# has incorporated a lot of functional features, and it is possible to rewrite the example in a more compact way using the LINQ extensions.
So here is another C# version -- a line-for-line translation of the F# code.
public static class FunctionalSumOfSquaresHelper
{
public static int SumOfSquares(int n)
{
return Enumerable.Range(1, n)
.Select(i => i * i)
.Sum();
}
}
However, in addition to the noise of the curly braces and periods and semicolons, the C# version needs to declare the parameter and return types, unlike the F# version.
Many C# developers may find this a trivial example, but still resort back to loops when the logic becomes more complicated. In F# though, you will almost never see explicit loops like this. See for example, this post on eliminating boilerplate from more complicated loops.
C#代码重写
最初的例子是用“远古风格”的C#写的。C#也包含了很多函数式特性,能用LINQ扩展来把代码重写得更简洁。
下面是另一个C#写的版本,从F#的代码一行行的翻译过来的。
...
然而,大括号和分号之类的“杂音”还在,参数和返回值的类型声明也少不了,还是不像F#版本那么简洁。
一些C#开发可能觉得这个例子不值一提,在遇到复杂的逻辑时,仍然靠循环来做。再看一个例子吧,教你解脱:http://fsharpforfunandprofit.com/posts/conciseness-extracting-boilerplate/

时间: 2024-08-08 08:39:21

F#之旅3 - F# PK C#:简单的求和的相关文章

F#之旅4 - 小实践之快排

参考文章:https://swlaschin.gitbooks.io/fsharpforfunandprofit/content/posts/fvsc-quicksort.html F#之旅4 - 小实践之快排 这次这篇呢,就不翻译了,因为原文确实是相当的简单.先贴一下能跑的代码: 这里贴的不是文本,如果你也想尝试一下,建议你抄一遍,或者理解之后自己写一遍.来看看都有那些要注意的点吧: 1.快排算法,这里用的递归的形式,把所有数分成三部分,[比第一个元素小的部分] [第一个元素] [比第一个元素

F# 之旅(上)

写在前面的话 解答一下在上一篇文章<在Visual Studio中入门F#>中有人的提问, 1. 问:是准备写 F# 系列吗?    答:当然不是,本人也是刚刚学习 F#,只是翻译微软官方的文档,但是我会尽力翻译更多的文章. 2. 问:你们的项目使用F#写的吗?    答:本人大三学生,也不是什么大佬,兴趣而已. 在这篇文章中 怎样运行示例代码 函数和模块 数字.布尔值和字符串 元组 管线和组成 列表.数组和序列 学习 F# 最好的方式是读写 F# 代码.本文将介绍 F# 语言的一些主要功能,

F#之旅0 - 开端

F#之旅0 - 开端 UWP的学习告一段落,CozyRSS的UWP版本并没有做.UWP跟wpf开发几乎一模一样,然后又引入了很多针对移动设备的东西,这部分有点像android.没啥太大的意思,不难,估计坑不少,但是暂时的没太大的欲望去玩. 学一门函数式编程语言,听起来就是一件不错的事情. 函数式编程,准确的来说应该是函数式编程这种编程范式,在很多中编程语言中都可以玩的.现在流行的js.python.lua.c++.java都有闭包了,至于惰性计算.常量,也好像不那么重要.但是既然特意说学一门函数

Integer.parseInt(f.trim())中String f要加trim()

如int a=Integer.parseInt(f.trim());语句中String 转换成int 时 f要加trim()方法,不然会抛出异常. Integer.parseInt(f.trim())中String f要加trim(),布布扣,bubuko.com

(打表+优化)简单的求和 -- zzuli -- 1783

http://acm.zzuli.edu.cn/problem.php?id=1783 1783: 简单的求和 Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 170  Solved: 31 SubmitStatusWeb Board Description 定义f(i)代表i的所有因子和(包括1和i),给定一个l,r.求f(l)+f(l+1)+...+f(r). Input 第一行输入一个t(t<1000),代表有t组测试数据,接下来每行输入两个数

简单的求和(打表)

简单的求和 Time Limit: 1 Sec  Memory Limit: 128 MB Submit: 130  Solved: 20SubmitStatusWeb Board Description 定义f(i)代表i的所有因子和(包括1和i),给定一个l,r.求f(l)+f(l+1)+...+f(r). Input 第一行输入一个t(t<1000),代表有t组测试数据,接下来每行输入两个数字l,r,(1<=l<=r<=1000000). Output 每行输出一个整数,代表

zzuli1783: 简单的求和---求因子和

1783: 简单的求和 Description 定义f(i)代表i的所有因子和(包括1和i),给定一个l,r.求f(l)+f(l+1)+...+f(r). Input 第一行输入一个t(t<1000),代表有t组测试数据,接下来每行输入两个数字l,r,(1<=l<=r<=1000000). Output 每行输出一个整数,代表和. Sample Input 2 1 2 3 4 Sample Output 4 11 #include <iostream> #include

F#之旅8 - 图片处理应用之动画二维码

首先,先介绍下什么是动画二维码.前些天在网上闲逛,突然看到一个开源项目,发现一种二维码的新玩法.https://github.com/sylnsfar/qrcode/blob/master/README-cn.md.二维码各种美化早就有看过,原理也大概知道,一是利用二维码的容错率,二是利用识别工具的纠错能力.这次的二维码,让我有点excited,居然把动画和二维码结合起来了.当然,具体把这种二维码叫什么,我也定不了,叫动画二维码.动态二维码.gif二维码都可以吧.动画二维码和之前的美化过的二维码

F#之旅2 - 我有特别的学F#技巧

原文地址:https://swlaschin.gitbooks.io/fsharpforfunandprofit/content/learning-fsharp/ Learning F#Functional programming languages need a different approach学习F#函数式编程语言需要不同的学习方法 Functional languages are very different from standard imperative languages, an