haskell - 使用函数式语言(例如 F#)的函数的参数名称

标签 haskell f# functional-programming ocaml named-parameters

我读过一本名为干净代码的书。我从书中得到的最强烈的信息之一是代码必须可读。我不明白为什么 F# 等函数式语言不将函数参数名称包含在智能感知或类型定义中?

比较

val copy: string -> string -> unit

val copy: sourceFile:string -> destinationFile:string -> unit

函数世界中的最佳实践是什么?我们应该更喜欢单参数函数吗?这就是干净代码所提倡的。或者我们应该对 2 个以上参数的所有函数使用记录

我知道一种解决方法是使用 static member 而不是 let 函数,但这不是一种函数式方法,不是吗?

编辑:

只是为了提供更多信息:

  • Haskell : addThree::Int -> Int -> Int -> Int
  • OCaml : Unix.unlink: (字符串 -> 单位)

当然还有其他人。它们只是不在类型定义中显示参数名称。

最佳答案

如果您实践类型化编程,即程序的许多语义内容可以静态地反射(reflect)在类型系统中,您会发现在许多(但不是所有)情况下,命名参数对于可读性来说不是必需的。

考虑 OCaml List 标准库中的以下示例。通过了解它们对列表进行操作,以及函数的名称(希望清楚:我们都支持好的名称选择),您会发现不需要解释参数的作用。

val append : α list -> α list
val flatten : α list list -> α list
val exists: (α -> α bool) -> α list -> bool
val map: (α -> β) -> α list -> β list
val combine : α list -> β list -> (α * β) list

请注意,最后一个示例很有趣,因为尚不清楚代码将做什么。事实上会有多种解释。 combine [1;2] [3;4] 返回 [(1,3); (2,4)] 而不是,例如 [(1,3); (1,4); (2,3); (2,4)]。也不清楚当两个列表长度不同时会发生什么(故障模式不清楚)。

不完全的函数可能会引发异常或不会终止,通常需要更多有关失败情况及其行为方式的文档。这是支持我们所谓的“纯编程”的一个强有力的论据,其中函数的所有行为都以返回值来表达(没有异常(exception),可观察的状态突变,或非终止),因此可以由类型系统静态捕获。

当然,这只适用于参数足够的函数;他们有一种类型,可以非常清楚地表明他们所做的事情。并非所有函数都是如此,例如考虑 String 模块的 blit 函数(我确信您最喜欢的语言也有这样的示例):

val blit : string -> int -> string -> int -> int -> unit

嗯?

出于这个原因,编程语言添加了对命名参数的支持。例如,在 OCaml 中,我们有允许命名参数的“标签”。相同的函数在 StringLabels 模块中导出为:

val blit : src:string -> src_pos:int -> dst:string -> dst_pos:int -> len:int -> unit

这样更好。是的,命名参数在某些情况下很有用。

但请注意,命名参数可用于隐藏不良的 API 设计(也许上面的示例也是针对这种批评的)。考虑:

val add : float -> float -> float -> float -> float -> float -> float * float * float

晦涩难懂,是吗?但随后:

type coord = {x:float; y:float; z:float}
val add : coord -> coord -> coord

这好多了,而且我不需要任何参数标签(可以说记录标签提供了命名,但实际上我可以在这里同样使用 float * float * float ;事实上,值记录可能包含命名(和可选?)参数也是一个有趣的评论)。

大卫·巴伯 develops the argument命名参数是语言设计的“拐杖”,用于篡改 API 设计者的懒惰,并且没有它们会鼓励更好的设计。我不确定我是否同意在所有情况下都可以有效地避免命名参数,但他的观点肯定与我文章开头的典型宣传一致。通过提高抽象级别(通过更多的多态/参数类型或更好的问题域抽象),您会发现减少了对参数命名的需求。

关于haskell - 使用函数式语言(例如 F#)的函数的参数名称,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15088450/

相关文章:

xml - 使用 XMLReader 的 F# XML 解析

scala - 最佳功能方法

f# - 在 F# 中非常简单的 RogueLike,使它更 "functional"

recursion - 为什么包含 Console.ReadLine() 的函数不完整?

Scala-惯用方式来计算交错数组的总和?

haskell - 如何检查字符串是否可以在 Haskell 中解析为某种类型?

haskell - 在删除不透明的 FFI 对象之前,垃圾回收需要多长时间?有可能以某种方式加快速度吗?

haskell - 从 Network.HTTP.Enumerator 迁移到 Network.HTTP.Conduit

haskell - 每个类型构造函数 (`Type -> Type` ) 都是某种仿函数吗

f# - 从 Console.In 读取的函数返回以前的值