导入haskell模块是否是一种合格的做法?
我知道导入限定名有助于避免名称冲突。我只是从可读性的角度来提问 由于不熟悉haskell标准库,在阅读haskell代码(主要来自在线书籍和教程)时,我发现有一件事很烦人,那就是当我遇到一个函数时,我不知道它是否属于导入的模块,或者稍后将由用户定义导入haskell模块是否是一种合格的做法?,haskell,Haskell,我知道导入限定名有助于避免名称冲突。我只是从可读性的角度来提问 由于不熟悉haskell标准库,在阅读haskell代码(主要来自在线书籍和教程)时,我发现有一件事很烦人,那就是当我遇到一个函数时,我不知道它是否属于导入的模块,或者稍后将由用户定义 来自C++背景,通常将它称为一个很好的做法,用名字空间调用标准库函数,例如STD::Debug。哈斯克尔也是这样吗?如果没有,您如何克服我上面提到的问题?来自: 始终使用显式导入列表或符合条件的导入进行标准和 第三方图书馆。这使得代码对更改更加健壮
来自C++背景,通常将它称为一个很好的做法,用名字空间调用标准库函数,例如STD::Debug。哈斯克尔也是这样吗?如果没有,您如何克服我上面提到的问题?
来自: 始终使用显式导入列表或符合条件的导入进行标准和 第三方图书馆。这使得代码对更改更加健壮 在这些图书馆里。例外:前奏曲因此,答案是肯定的。使用合格的导入被认为是标准库和第三方库(Prelude除外)的良好实践。但是对于带有符号的中缀函数(比如
),您可能需要显式导入它,因为限定的导入看起来不太好。我不太喜欢限定名称,因为它们会使代码变得混乱。只有那些使用与前奏曲函数冲突的名称的模块才应该始终被导入,这些模块通常有明确的建议
对于广泛使用的模块,如Control.Applicative
,没有太多理由不导入不合格的模块;大多数程序员应该知道其中的所有内容。对于不太知名的包中的模块,如果它们执行非常特定的操作,或者为了避免单个名称的冲突,您可以使用显式的导入列表,例如,导入数据.list(sortBy)
,导入系统.Random.Shuffle(shuffleM)
——这样,您就不必在代码中添加限定符,然而,在imports部分查找标识符会立即告诉您它来自何处(这类似于使用std::cout;)。但老实说,我发现将模块加载到ghci并使用它更方便
*ClunkyModule>:i奇怪的函数
看看它的定义
关于合格的导入或明确的导入列表,有一点我倾向于忽略:它们使您的包更加经得起未来的考验。如果某个模块的新版本停止导出您需要的项目,或者另一个模块引入了冲突名称,那么显式导入将立即向您指出问题所在。我和您的感觉相同。如果我在一个我不熟悉的模块中看到
functionName
,那么我就不知道它来自多个导入中的哪一个。这里的“陌生模块”也可以指我自己过去写的模块!我目前的风格是这样的,但它并不是被普遍接受的。这种风格的用户可能是极少数
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 ...
然而,我几乎从不限定中缀运算符。我自己的一套规则
1) 尝试在不重命名的情况下不导入任何符合条件的内容B.ByteString
比Data.ByteString.ByteString
更具可读性。对于真正普遍存在的模块,例如Control.Monad
,可能会有例外
2) 不要导入整个模块,导入特定的函数/类型/类,除非它们太多。这样,如果有人想找出某个函数的来源,他只需在文件开头搜索该函数的名称
3) 导入密切相关的模块,将其重命名为相同的名称,除非导入的函数发生冲突,或者其中两个模块作为一个整体导入,而没有导入列表
4) 如果可能,尽量避免使用来自不同模块的同名函数,即使这些模块的重命名方式不同。如果有人知道函数
X.foo
的作用,他很可能会被函数Y.foo
弄糊涂。如果是不可避免的,考虑创建一个单独的、非常小的模块,它既可以导入函数,又可以在不同名称下导出它们。 C++中的问题是,如果使用不合格的调用,ADL可以将您拧过去。在Haskell中,最糟糕的情况是出现歧义错误,除非一个库完全删除该函数,而另一个库添加该函数。在这种情况下,您可能会遇到一个类型错误-如果不是,那么函数很可能是兼容的。我明白您的意思,但我发现在读取时从ghci或文件头查找函数名是相当不方便的,尤其是当文件很长,并且有多个函数存在问题时。一旦我了解了更多的图书馆,也许我会忘记这一点。当我看到像split这样的函数名时,我不知道它是来自Data.List还是用户定义的。不过,Ghci只适用于当前编译的代码。@Ben:如果你得到一段非编译代码,并且应该理解它,那么你真的很不走运。但为什么会有人这样做?@leftaroundabout也许你在一个团队中工作,不得不去接别人正在进行的工作。也许你已经在Hackage上找到了你所需要的库,但是它已经两年没有更新了,你正在尝试将它转发到现代依赖项。也许你只是在接一个半途而废的项目,而你已经有一段时间没做了。(我经常诅咒我过去的自己缺乏远见;我认为这是开发者天生的条件)@Ben True。。。正如我所说,我也不能为自己的这种远见感到自豪。但实际上,通过在cabal文件中正确指定依赖项版本来避免此类问题似乎更简单,因此即使在编译之前,过时的包也会指向依赖项问题。(当然,我也倾向于忽略这种可能性…)下降到3和4。可追溯性问题。