我通常坚信在我编程的大多数语言中都使用名称空间(合格的模块名称),因为很容易一目了然地知道某个标识符的来源。在Haskell中,还有一个额外的优点,即避免使用Prelude函数进行常见的名称冲突。
但是,我觉得必须在中缀符号(或其他短的DSL-y标识符)上放置一个名称空间看起来很奇怪,所以我很想重新出口值,如下所示:
import qualified Data.Sequence as Seq
(|>) = (Seq.|>)
(<|) = (Seq.<|)
现在困扰我的是那个
手动重新出口价值感觉就像无聊的样板。
手动重新导出值围绕现有的模块系统,似乎不适用于数据构造函数(可能还有其他我未遇到过的东西)
import qualified Data.Sequence as Seq
(:>) = (Seq.:>) --gives me a parse error:
--"Not in scope: data constructor `:>'"
如何协调中缀符号和命名空间?我应该放弃并学习命名空间吗?是否已经建立了关于命名空间和符号的Haskell最佳实践?
答案 0 :(得分:19)
嗯,你可以做的一件事是导入两次:
import Data.Sequence ((|>), (<|), ViewR ((:>)))
import qualified Data.Sequence as Seq
这将仅导入:>
,|>
和<|
不合格,其他所有内容都合格。请注意,由于:>
是数据构造函数,因此您还必须导入其数据类型(ViewR
),但不必须导入剩余的ViewR
构造函数。
此外,如果您担心冲突,您应该只是隐藏操作员:
import Prelude hiding ((.))
如果你正在使用一个理智的库,与Prelude的冲突意味着库函数被设计为替换该Prelude函数(例如Control.Category
),所以你想让它替换它默认含义。
就最佳实践而言,我从未见过任何人使用合格的运营商,除非发生冲突或他们在GHCi。总而言之,即使考虑到了解运营商所在位置的优势,也会使代码的可读性降低。
答案 1 :(得分:8)
我通常导入不合格的类型名称,构造函数和运算符,以及其他所有限定条件:
import Data.Sequence (Seq, ViewL(..), ViewR(..), (|>), (<|))
import qualified Data.Sequence as Seq
文档推荐Data.Map和其他标准容器使用这种双重导入的非限定类型名称样式。
但是,您无法始终导入不合格的运算符 - 例如,如果您在同一模块中使用Array
/ Vector
和Map
,则无法导入来自两个不合格的(!)
。在那种情况下,我通常只使用它合格。它看起来很奇怪,但它比其他选项更好(比如为其中一个提出你自己的名字以避免冲突)。当然,如果它阻止人们使用不安全的函数,例如(Data.Map.!)
:)