在F#中功能性地写入平方和

Da *_*est 2 f# functional-programming

所以我有这4个例子,其中3个是我从这个youtube视频中得到的.

我刚刚参加了关于函数式编程的课程(在Racket中),如果我对F#的基本理解是对的,我就是这样.

let data = [1.;2.;3.;4.]

let sqr x = x * x

// Bad, very bad   
let sumOfSquareI nums =
    let mutable acc = 0.0
    for x in nums do
        acc <- acc + sqr x
    acc

// Better than above, but may cause stack overflow with very long list    
let rec sumOfSquareF1 nums = 
    match nums with 
    | [] -> 0.0
    | h::t -> sqr h + sumOfSquareF1 t

// much much better, uses tail-recursion, no stack overflow  
let sumOfSquareF2 nums =
    let rec sumOfSquareLocal nums acc = 
        match nums with
        | [] -> acc
        | h::t -> sumOfSquareLocal t (acc + sqr h)
    sumOfSquareLocal nums 0.0

// seems to be idiomatic F#, but is it better than tail-recursive version?    
let sumOfSquare nums =
    nums
    |> Seq.map sqr
    |> Seq.sum    

sumOfSquare data
sumOfSquareI data
sumOfSquareF1 data
sumOfSquareF2 data
Run Code Online (Sandbox Code Playgroud)

最后两个函数之间有什么真正的区别吗?这个比那个好吗?在F#中编写功能代码时,我应该多久使用一次|>运算符(这对我来说是全新的)?

另一件事是在F#中创建列表有不同的方法吗?我从视频中提取的内容似乎......笨重.

Lee*_*Lee 6

是的,你应该更喜欢使用SeqList模块中的高阶函数而不是显式递归.您还可以使用sumBy:

let sumOfSquare nums = nums |> Seq.sumBy sqr
Run Code Online (Sandbox Code Playgroud)


Van*_*oiy 5

关于编程风格或范式的讨论很容易变成基于意见的推理。让我们来看看每个函数在现实世界中真正重要的含义。

版本 1:命令式

这一项需要五行琐碎的行。几乎每个人都可以阅读它。“状态机”是单个变量,易于验证。它不是通用的,但LanguagePrimitives.GenericZero不是0.0可以解决这个问题,尽管需要付出一定的代价。

与其他人相比,我不会称之为“糟糕,非常糟糕”。除非你让编程成为一种崇拜,必须通过神圣的功能真理来摧毁命令式的异常。虽然它也不是最小的。

版本 2:递归计算

它相当易读,少用一行。同样,不是通用的,但通用零可以解决这个问题。但是,这个函数会导致栈变大!使用它的人会在第一次测试中看到它运行良好,直到突然,性能下降或整个程序崩溃!

我认为这客观上是所提出的解决方案中最糟糕的!您不想在生产代码中使用它!

版本 3:嵌套尾递归函数

同样,这可以变得通用。这个运行良好并且功能强大,但它有 6 行,我不会再将其中的三行称为微不足道了。

这是纯粹的,但老实说,如果我必须在这个和命令式变体之间做出选择,我不太确定。

版本 4:调用高阶函数

简短易读,通用而不使用奇怪的原语!为什么你会怀疑这是四人中的赢家?

额外版本:根本没有

高阶函数为此效果很好,这还不是结束。Seq.sumBy sqr(我看到李在他的回答中击败了我)完成了这项工作。由于这仅比 长sumOfSquares,在生产代码中,可能根本没有理由定义额外的函数。

可读性是关键

当您就何时使用管道运算符等寻求建议时,答案必须针对将阅读代码的人进行优化。编译器肯定不在乎你扔了多少括号。考虑谁会阅读代码,并为此进行优化。

在主要为自己编写代码时,请使用任何花费最少时间进行导航和解释的组合。管道非常棒,可以避免像很多很难计算的右括号之类的问题。

PS:有很多方法可以初始化列表。在这种情况下,[1. .. 4.]将完成这项工作。