什么是if-then语句的功能替代?

Bob*_*Bob 44 f# functional-programming

我一直在学习F#和函数式编程,并试图以功能的方式做事.但是,当我重写一些我已用C#编写的代码时,我会陷入简单的if-then语句(只做一些事情而不返回值).我知道你可以在F#中解决这个问题:

if expr then do ()
Run Code Online (Sandbox Code Playgroud)

但是,我认为这是编码的必要方法?也许我对功能编程学得不够,但它对我来说似乎没什么用.我认为功能方法是组合函数和表达式,而不是简单地一个接一个地执行语句,这是if-then似乎鼓励的.

所以,我错过了什么,如果 - 那么在功能世界中是完美的吗?如果没有,这种陈述的功能等同物是什么?我怎么能拿一个if-then然后把它变成功能呢?

编辑:我可能会问错误的问题(对不起,对于函数式编程来说仍然相当新):让我们采用一个真实世界的例子让我甚至问这个问题:

if not <| System.String.IsNullOrWhiteSpace(data) then do
    let byteData = System.Text.Encoding.Unicode.GetBytes(data)
    req.ContentLength <- int64 byteData.Length
    let postStream : System.IO.Stream = req.GetRequestStream()
    postStream.Write(byteData, 0, byteData.Length)
    postStream.Flush()
    postStream.Dispose()
Run Code Online (Sandbox Code Playgroud)

if-then的主体不返回任何内容,但我不知道如何使其更具功能性(如果可能的话).我不知道最小化命令式代码的正确技巧.考虑到F#的性质,直接运输我的C#相当容易,但是我很难将其转换为功能.每次我在C#中使用if语句,并且我正在尝试将其传输到F#时,我感到气馁,因为我无法想到一种方法来使代码更具功能性.

Tom*_*cek 35

尚未到目前为止提到的重要一点是之间的区别if .. then .. else,并if .. then没有else分支.

If 用函数式语言

功能解释if是它是一个评估某个值的表达式.要评估if c then e1 else e2您的价值,请评估条件c,然后根据条件评估e1或评估e2.这给你的结果if .. then .. else.

如果你有if c then e,那么你不知道评估结果应该c是什么false,因为没有else分支!以下显然没有意义:

let num = if input > 0 then 10
Run Code Online (Sandbox Code Playgroud)

在F#中,具有副作用的表达式printf "hi"返回类型的特殊值unit.该类型只有一个值(写为()),因此您可以编写if只在一个案例中起作用的值:

let u = if input > 0 then printf "hi" else ()
Run Code Online (Sandbox Code Playgroud)

这总是评估为unit,但在true分支中,它也执行副作用.在false分支中,它只返回一个unit值.在F#中,您不必else ()手动编写位,但从概念上讲,它仍然存在.你可以写:

let u = if input > 0 then printfn "hi"
Run Code Online (Sandbox Code Playgroud)

关于你的附加例子

代码对我来说非常好.当你必须处理势在必行的API(比如许多.NET库)时,最好的选择是使用命令功能,比如if使用unit返回分支.

您可以使用各种调整,例如使用option<string>(而不是string使用null或使用空字符串)来表示您的数据.这样,您可以None用来表示缺失的数据,其他任何东西都是有效的输入.然后,您可以使用一些高阶函数来处理选项,例如Option.iter,如果存在值,则调用给定函数:

maybeData |> Option.iter (fun data ->
    let byteData = System.Text.Encoding.Unicode.GetBytes(data)  
    req.ContentLength <- int64 byteData.Length  
    use postStream = req.GetRequestStream()  
    postStream.Write(byteData, 0, byteData.Length) )
Run Code Online (Sandbox Code Playgroud)

这不是必须的,但它更具说服力,因为你不必if自己写.顺便说一句:use如果你想要自动Dispose对象,我也建议使用.


pad*_*pad 14

if-then在功能世界中没有任何问题.

你举的例子实际上类似于let _ = expr因为expr有副作用,我们忽略它的返回值.一个更有趣的例子是:

if cond then expr
Run Code Online (Sandbox Code Playgroud)

这相当于:

match cond with
| true -> expr
| false -> ()
Run Code Online (Sandbox Code Playgroud)

如果我们使用模式匹配.

当条件很简单或只有一个条件表达式时,if-then比模式匹配更具可读性.此外,值得注意的是,函数式编程中的所有内容都是表达式.所以if cond then expr实际上是捷径if cond then expr else ().

如果 - 那么本身并不是必要的,使用if-then作为陈述是一种必要的思维方式.根据我的经验,函数式编程更多地是关于思维方式而不是编程语言中的具体控制流程.

编辑:

您的代码完全可读.一些小问题是摆脱冗余do关键字,类型注释和postStream.Dispose()(通过使用use关键字):

if not <| System.String.IsNullOrWhiteSpace(data) then
    let byteData = System.Text.Encoding.Unicode.GetBytes(data)
    req.ContentLength <- int64 byteData.Length
    use postStream = req.GetRequestStream()
    postStream.Write(byteData, 0, byteData.Length)
    postStream.Flush()
Run Code Online (Sandbox Code Playgroud)

  • 在实践中,`do`有其信号代码片段的作用,它具有副作用并创建一个新的范围(当使用`using`函数时很重要). (2认同)

Chu*_*uck 10

这不是if-expression的必要条件,而是if-expression中的内容.例如,let abs num = if num < 0 then -num else num编写abs函数是一种完全有效的方法.它接受一个参数并返回该参数的变换而没有副作用.但是,当你拥有"代码,只有做一些事情,而不是返回一个值," 然后你写的东西是不是纯粹的功能性.函数式编程的目标是最小化程序中可以用这种方式描述的部分.你如何写你的条件是切向的.


小智 8

为了编写复杂的代码,您需要在某个时刻进行分支.您可以使用非常有限的方法,并且所有这些方法都需要通过一段代码的逻辑流程.如果你想避免使用if/then/else,可以使用loop/while/repeat作弊 - 但这会使你的代码维护和阅读的合理性降低.

函数式编程并不意味着你不应该一个接一个地执行语句 - 它只是意味着你不应该有一个可变状态.每次调用时,每个函数都需要以相同的方式可靠地运行.数据处理方式的任何差异都需要通过传入的数据来计算,而不是从调用函数的任何内容中隐藏的某些触发器.

例如,如果我们有一个函数foo(int, bool)返回一些不同的函数,具体取决于bool是true还是false,那么几乎肯定会在if某处发表声明foo().那是完全合法的.什么是不合法的是让一个函数foo(int)返回不同的函数,这取决于它是否是第一次在程序中调用它.这是一种"有状态"的功能,它使维持该计划的任何人都感到生活困难.


Tim*_*Tim 6

如果您的if语句具有返回值并且没有副作用,则认为它是功能正常的。

假设您要编写相当于以下内容的内容:

if(x > 3) n = 3; else n = x;

您可以使用if命令中的return语句来代替这样做:

let n = (if x > 3 then 3 else x)

这个假设if突然起作用,因为它没有副作用。它只返回一个值。可以将其视为某些语言中的三元运算符int n = x>3?3:x;

  • 这就是为什么`a?b:c`称为三元。 (9认同)
  • 'e?e:e`运算符通常称为**条件运算符**。三元运算符是带有三个参数的任何运算符。 (3认同)