Haskell下划线与显式变量

Haskell下划线与显式变量,haskell,Haskell,我已经学习Haskell几个星期了,我有一个关于下划线(\uu)作为函数参数使用的问题。我想我的问题最好用一个具体的例子来回答。假设我想定义一个函数,根据提供的索引提取列表元素。是的,我意识到(!!)已经是预定义的。我可以通过以下两种方式定义函数(我相信还有更多): 第1版 indexedElement :: [a] -> Int -> a indexedElement xs n | n < 0 = error "Index can not be neg

我已经学习Haskell几个星期了,我有一个关于下划线(
\uu
)作为函数参数使用的问题。我想我的问题最好用一个具体的例子来回答。假设我想定义一个函数,根据提供的索引提取列表元素。是的,我意识到
(!!)
已经是预定义的。我可以通过以下两种方式定义函数(我相信还有更多):

第1版

indexedElement             :: [a] -> Int -> a
indexedElement xs n | n < 0 = error "Index can not be negative."
indexedElement [] n         = error "Index must be smaller than the length of the list."
indexedElement (x:xs) 0     = x
indexedElement (x:xs) n     = indexedElement xs (n - 1)
indexedElement::[a]->Int->a
indexedElement xs n | n<0=错误“索引不能为负。”
indexedElement[]n=error“索引必须小于列表的长度。”
索引删除(x:xs)0=x
索引删除(x:xs)n=索引删除xs(n-1)
第2版

indexedElement            :: [a] -> Int -> a
indexedElement _ n | n < 0 = error "Index can not be negative."
indexedElement [] _        = error "Index must be smaller than the length of the list."
indexedElement (x:_) 0     = x
indexedElement (_:xs) n    = indexedElement xs (n - 1)
indexedElement::[a]->Int->a
indexedElement n | n<0=错误“索引不能为负。”
indexedElement[]=error“索引必须小于列表的长度。”
索引删除(x:uu0=x
indexedElement(ux:xs)n=indexedElement xs(n-1)
这两个版本显然非常相似。两者之间的唯一区别是使用显式变量或下划线。对我来说,
意味着可以在那里写任何东西,而像
n
这样的显式变量更明显地表明参数必须是整数。因此,我更喜欢版本1;但是
(!!)
的GHC源代码编写方式与版本2类似。第二个版本在功能上有优势吗?如果不是的话,“硬核”Haskell程序员会对版本1提出异议吗?我理解以一致的方式编写代码的重要性,因此我尝试遵循特定语言编程的“不成文规则”。这是一个我更喜欢第一个版本的例子,我不认为这会使代码更难阅读。我不知道这是因为我的纯数学背景还是什么,但我想听听你们更老练的哈斯克尔兽医们的想法

第二个版本在功能上有优势吗

我认为他们在操作上没有任何区别。但我发现第二个版本更具可读性<代码>\u表示它根本没有被使用。因此,在阅读代码时,我可以忽略它,只关注其他参数。而在第一个版本中,我会认为
n
是定义的,但可能作者忘记使用它了?或者这个论点不是必需的。第二个版本只是避免了这种精神负担。但这只是我的意见。:)

事实上,如果启用警告标志(
-Wall
)并编译代码,它将为您的第一个版本发出警告:

[1 of 1] Compiling Main             ( code.hs, code.o )

code.hs:2:16: Warning: Defined but not used: ‘xs’

code.hs:3:19: Warning: Defined but not used: ‘n’

code.hs:4:19: Warning: Defined but not used: ‘xs’

code.hs:5:17: Warning: Defined but not used: ‘x’

code.hs:8:17: Warning: Defined but not used: ‘xs’

我不确定性能差异(您可以尝试输出两个版本的核心,看看是否有任何差异),但大多数Haskeller更喜欢第二个版本,因为它减少了需要绑定的名称数量。
表示任何值都可以到达那里(只要它是正确的类型,由类型签名给出。虽然使用
n
表示整数可能会感觉更自然,即使它不在使用中,但请记住,并非每个人都会有这种偏见。您可以通过命名变量
\n
,这会在使用
-Wall
时关闭警告表示没有使用该变量,并同时对其命名。@basketballfan22,luqui的方法在最近也变得很惯用,我非常喜欢它。@Sibi,我确实看到过它,所以它几乎肯定会被一些人使用,很可能包括
base
,但我不能特别指出m顶部的任何东西y head。@Bheklillr,当然不会有任何性能差异。Alpha转换只会影响反射过多或编译器不正常的语言中的任何东西。非常感谢。正如我在帖子中提到的,我已经很久没有用Haskell编程了;因此,我甚至不知道
-Wall
。如何改变它on?我是否只需在源代码的最开始处键入
-Wall
;如果是,是否应在任何导入之前键入?@basketballfan22:这是编译器的命令行选项。如果您使用
ghc
命令手动编译,则在那里提供它。如果您使用的是Cabal或Stack之类的构建工具,则它们的文档我会说如何配置项目的GHC选项。@LuisCasillas:啊!太棒了。谢谢你的帮助。@basketballfan22,另一个选项是将
{-#options\u GHC-Wall}
放在
.hs
文件中
模块
行上方的某个地方。