Functional programming 如何编写更清晰的函数式代码?
我的代码在风格和外观上都越来越具有功能性 这里我有一个函数,我尽量保持它的通用性,传递一个过滤函数和一个计算函数作为参数Functional programming 如何编写更清晰的函数式代码?,functional-programming,f#,Functional Programming,F#,我的代码在风格和外观上都越来越具有功能性 这里我有一个函数,我尽量保持它的通用性,传递一个过滤函数和一个计算函数作为参数 let calcError filter (fcalc:'a -> float) (arr:'a array) = arr |> Array.filter filter |> Array.map fcalc |> Array.average 签名为: val calcError : fi
let calcError filter (fcalc:'a -> float) (arr:'a array) =
arr |> Array.filter filter
|> Array.map fcalc
|> Array.average
签名为:
val calcError : filter:('a -> bool) -> fcalc:('a -> float) -> arr:'a array -> float
我相信这是相当标准的,在部分应用程序中使用calcError
然而,Array.average将在数组大小为0或为null时引发异常,这在我的情况下不会发生
我不太喜欢F中的异常,我更喜欢使用浮点输出或结果
然后,我会考虑用这种方式编写代码,但我不确定这是一种在我试图获得的功能性思维中正确的方式。当然,任何其他解决方案都是受欢迎的,我可能能够适应其他类似问题
谢谢大家
我心目中的解决办法是:
let calcError2 filter (fcalc:'a -> float) (arr:'a array) =
let subarr = arr |> Array.filter filter
match subarr.Length with
| 0 -> Result.Error "array length 0"
| _ -> subarr |> Array.map fcalc
|> Array.average
|> Result.Ok
这是一种方法:
let tryCalcError filter (fcalc:'a -> float) (arr:'a array) =
arr |> Array.filter filter
|> Array.map fcalc
|> function
| [||] -> None
| arr -> Array.average arr |> Some
它遵循前缀为try的约定,以指示返回值是一个选项。你可以从以下几个方面看到这个惯例。试试看。。。函数,如tryFind、tryHead、tryLast、tryItem、tryPick。这是一种方法:
let tryCalcError filter (fcalc:'a -> float) (arr:'a array) =
arr |> Array.filter filter
|> Array.map fcalc
|> function
| [||] -> None
| arr -> Array.average arr |> Some
它遵循前缀为try的约定,以指示返回值是一个选项。你可以从以下几个方面看到这个惯例。试试看。。。函数,如tryFind、tryHead、tryLast、tryItem、tryPick。这里是另一个带有辅助函数的版本
let calcError filter (fcalc:'a -> float) (arr:'a array) =
let safeAverage ar = if Array.isEmpty ar then None else Some(Array.average ar)
arr |> Array.filter filter
|> Array.map fcalc
|> safeAverage
let nat arr = if Array.isEmpty arr then None else Some(arr)
let calcError filter (fcalc:'a -> float) (arr:'a array) =
arr |> Array.filter filter
|> Array.map fcalc
|> nat
|> Option.bind (Some << Array.average )
此外,您可以将数组转换为选项,以便将其与任何其他不安全的数组函数一起使用
let calcError filter (fcalc:'a -> float) (arr:'a array) =
let safeAverage ar = if Array.isEmpty ar then None else Some(Array.average ar)
arr |> Array.filter filter
|> Array.map fcalc
|> safeAverage
let nat arr = if Array.isEmpty arr then None else Some(arr)
let calcError filter (fcalc:'a -> float) (arr:'a array) =
arr |> Array.filter filter
|> Array.map fcalc
|> nat
|> Option.bind (Some << Array.average )
这是一个使用无点样式的更紧凑、更高效的版本
let calcError filter (fcalc:'a -> float) =
Option.bind (Some << (Array.averageBy fcalc)) << nat << Array.filter filter
我花了一段时间才真正体会到创建许多小功能的价值。希望能有帮助 这里是另一个带有帮助函数的版本
let calcError filter (fcalc:'a -> float) (arr:'a array) =
let safeAverage ar = if Array.isEmpty ar then None else Some(Array.average ar)
arr |> Array.filter filter
|> Array.map fcalc
|> safeAverage
let nat arr = if Array.isEmpty arr then None else Some(arr)
let calcError filter (fcalc:'a -> float) (arr:'a array) =
arr |> Array.filter filter
|> Array.map fcalc
|> nat
|> Option.bind (Some << Array.average )
此外,您可以将数组转换为选项,以便将其与任何其他不安全的数组函数一起使用
let calcError filter (fcalc:'a -> float) (arr:'a array) =
let safeAverage ar = if Array.isEmpty ar then None else Some(Array.average ar)
arr |> Array.filter filter
|> Array.map fcalc
|> safeAverage
let nat arr = if Array.isEmpty arr then None else Some(arr)
let calcError filter (fcalc:'a -> float) (arr:'a array) =
arr |> Array.filter filter
|> Array.map fcalc
|> nat
|> Option.bind (Some << Array.average )
这是一个使用无点样式的更紧凑、更高效的版本
let calcError filter (fcalc:'a -> float) =
Option.bind (Some << (Array.averageBy fcalc)) << nat << Array.filter filter
我花了一段时间才真正体会到创建许多小功能的价值。希望能有帮助 我觉得你的代码不错。唯一不同的是,我不会使用match来测试数组是否为空-您没有绑定任何变量,并且只有两个案例,因此您可以在这里使用if表达式 另外两个小调整是,我使用的是数组。我想看看数组是否为空,这可能在这里没有效果,但如果使用序列,它将比检查长度更快,我还使用averageBy,而不是map后跟average:
我觉得你的代码不错。唯一不同的是,我不会使用match来测试数组是否为空-您没有绑定任何变量,并且只有两个案例,因此您可以在这里使用if表达式 另外两个小调整是,我使用的是数组。我想看看数组是否为空,这可能在这里没有效果,但如果使用序列,它将比检查长度更快,我还使用averageBy,而不是map后跟average:
我觉得不错。我可能会尝试将错误案例的消息更改为更详细的消息,例如,过滤后数组为空,但我认为很多人不会对您提出的解决方案有异议。请查看:查看@BentTranberg页上的tryCatch函数,我喜欢tryCatch方法。我用这本圣经研究了ROP,但没有想到tryCatch函数。谢谢我觉得不错。我可能会尝试将错误案例的消息更改为更详细的消息,例如,过滤后数组为空,但我认为很多人不会对您提出的解决方案有异议。请查看:查看@BentTranberg页上的tryCatch函数,我喜欢tryCatch方法。我用这本圣经研究了ROP,但没有想到tryCatch函数。谢谢事实上,我去创建了一个额外的函数数组。tryAverage,感谢inputAn更好的解决方案。实际上,我去创建了一个额外的函数数组。tryAverage,感谢inputAn更好的解决方案。我发现这是一个从功能上解决这个问题的优雅方法。我发现这是一个从功能上解决这个问题的优雅方法。