我知道导入限定名称有利于避免名称冲突。我纯粹从可读性的角度来问。
不熟悉haskell标准库,我在阅读haskell代码(主要来自在线书籍和教程)时发现的一件事是,当我遇到一个函数时,我不知道它是否属于一个导入的模块或稍后将由用户定义。
来自C ++背景,通常认为使用命名空间调用标准库函数是一种很好的做法,例如std :: find。 haskell是一样的吗?如果没有,那么你如何克服我上面提到的问题?
答案 0 :(得分:8)
始终对标准和。使用显式导入列表或限定导入 第三方图书馆。这使代码对更改更加健壮 在这些图书馆。例外:序曲。
所以,答案是肯定的。除Prelude之外,使用合格导入被认为是标准和第三方库的良好实践。但是对于带符号的中缀函数(类似于<|*|>
),您可能希望显式导入它,因为合格的导入在它上面看起来不太好。
答案 1 :(得分:6)
我不太喜欢合格的名字,IMO他们比较混乱代码。应该始终导入限定的唯一模块是那些使用与前奏函数冲突的名称的模块 - 这些模块通常有明确的建议,in the documentation。
对于广泛使用的模块,例如Control.Applicative
,没有太多理由不进行不合格的导入;大多数程序员都应该知道那里的所有内容。对于来自不太知名的软件包的模块,这些模块可以执行非常具体的操作,或者为了避免单个名称的冲突,您可以使用显式导入列表,例如: import Data.List (sortBy)
,import System.Random.Shuffle (shuffleM)
- 这样,您就不必使用限定符来丢弃代码,但在导入部分中查找标识符可以立即告诉您它来自哪里(这类似于using std::cout;
)。但老实说,我发现将模块加载到ghci并使用
* ClunkyModule&GT; :我奇怪的功能
查看它的定义。
对于我倾向于忽视的合格进口或明确的进口清单,我们有一个很好的观点:它们使您的包装更具有前瞻性。如果某个模块的新版本停止导出您需要的项目,或者另一个模块引入了冲突名称,那么显式导入将立即指出您的问题。
答案 2 :(得分:2)
我和你一样。如果我在一个我不熟悉的模块中看到functionName
,那么我不知道它来自哪个导入。 &#34;不熟悉的模块&#34;这里也可以指我自己过去写的一个!我现在的风格如下,但它绝不是普遍接受的。这种风格的用户可能只占极少数。
import qualified Long.Path.To.Module as M
... use M.functionName ...
或者如果我想要更清晰
import qualified Long.Path.To.Module as Module
... use Module.functionName ...
我很少完全符合资格
import qualified Long.Path.To.Module
... use Long.Path.To.Module.functionName ...
但是,我几乎从不认定中缀运营商。
答案 3 :(得分:1)
我自己的一套规则。
1)尽管没有重命名,请尽量不导入任何合格的内容。 B.ByteString
比Data.ByteString.ByteString
更具可读性。可以对真正无处不在的模块进行例外处理,例如Control.Monad
。
2)不要导入整个模块,导入特定的函数/类型/类,除非它们太多。这样,如果有人想知道某些功能来自何处,他只需在文件开头搜索该功能的名称即可。
3)导入密切相关的模块,将它们重命名为相同的名称,除非导入的函数冲突,或者其中两个作为整体导入,没有导入列表。
4)如果可能,尽量避免在不同模块中使用具有相同名称的功能,即使这些模块的重命名方式不同。如果有人知道X.foo
有什么功能,他很可能会被函数Y.foo
搞糊涂。如果这是不可避免的,请考虑创建一个单独的,非常小的模块,该模块导入两个函数并以不同的名称导出它们。