如何处理带有限定名称的丑陋中缀符号
我通常坚信在我编程的大多数语言中使用命名空间(限定模块名称),因为一眼就知道某个标识符来自哪里是非常好的。在 Haskell 中,还有一个额外的优点,可以避免与 Prelude 函数发生常见名称冲突。
但是,我觉得必须在中缀符号(或其他简短的 DSL-y 标识符)上放置命名空间看起来非常奇怪,所以我很想重新导出值,如下所示:
import qualified Data.Sequence as Seq
(|>) = (Seq.|>)
(<|) = (Seq.<|)
现在困扰我的是
手动重新导出值感觉就像无聊的样板文件。
手动重新导出值会绕过现有的模块系统,并且似乎不适用于数据构造函数(可能还有我尚未遇到的其他事情)
导入合格的Data.Sequence作为Seq (:>) = (Seq.:>) --给我一个解析错误: --“不在范围内:数据构造函数`:>'”
如何协调中缀符号和命名空间?我应该放弃并学习命名一切吗?是否有关于命名空间和符号的已建立的 Haskell 最佳实践?
I am normally a firm believer of using namespaces (qualified module names) in most languages I program in since it is very good to know at a glance where a certain identifier came from. In Haskell there is also the added advantage of avoiding common name clashes with Prelude functions.
However, I feel like having to put a namespace on an infix symbol (or other short, DSL-y identifiers) looks really weird so I am tempted to reexport values, like this:
import qualified Data.Sequence as Seq
(|>) = (Seq.|>)
(<|) = (Seq.<|)
What is bugging me now is that
Manually reexporting values feels like boring boilerplate.
Manually reexporting values goes around the existing module system and does not seem to work with data constructors (and possibly other things I didn't come across yet)
import qualified Data.Sequence as Seq (:>) = (Seq.:>) --gives me a parse error: --"Not in scope: data constructor `:>'"
How do I reconcile infix symbols and namespacing? Should I just give up and learn to namespace everything? Are there estabilished Haskell best-practices regarding namespacing and symbols?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
那么,您可以做的一件事就是导入它两次:
这将仅导入
:>
、|>
和<|
不合格的,让其他一切都合格。请注意,由于:>
是数据构造函数,因此您还必须导入其数据类型 (ViewR
),但您不必导入 ViewR 的其余构造函数。此外,如果您担心冲突,则应该适当隐藏该运算符:
如果您使用的是正常的库,则与 Prelude 的冲突意味着该库函数旨在替换该 Prelude 函数(例如
Control.Category
)所以你想让它取代默认的含义。就最佳实践而言,我从未见过有人使用合格的操作员,除非存在冲突或他们在 GHCi。总而言之,即使考虑到知道操作符来自哪里的优势,它也会使代码的可读性大大降低。
Well, one thing you can do is import it twice:
This will import only
:>
,|>
and<|
unqualified, leaving everything else qualified. Note that since:>
is a data constructor, you also have to import its data type (ViewR
), but you do not have to import the rest ofViewR
's constructors.Additionally, if you're worried about conflicts, you should just hide the operator as appropriate:
If you're using a sane library, a conflict with Prelude means the library function is designed to replace that Prelude function (e.g.
Control.Category
) so you want to let it replace the default meaning.As far as best practices go, I have never seen anybody use qualified operators unless there is a conflict or they're at GHCi. All told, even factoring in the advantage of knowing where an operator is from, it makes the code much less readable.
我通常导入类型名称、不合格的构造函数和运算符,以及其他所有合格的内容:
Data.Map 和其他标准容器。
不过,您不能总是导入不合格的运算符 - 例如,如果您在同一模块中使用
Array
/Vector
和Map
,您无法从两个不合格的对象中导入(!)
。在这种情况下,我通常只会使用它。它看起来很奇怪,但它比其他选项更好(比如为其中一个选择你自己的名字以避免冲突)。当然,如果它阻止人们使用像(Data.Map.!)
这样的不安全函数,也许这是一件好事:)I generally import the type names, constructors and operators unqualified, and everything else qualified:
This double-import, unqualified-type-name style is recommended by the documentation to Data.Map and other standard containers.
Still, you can't always import operators unqualified — for instance, if you're using
Array
/Vector
andMap
in the same module, you can't import the(!)
from both unqualified. In that case, I'd usually just use it qualified. It looks weird, but it's better than the other options (like coming up with your own name for one of them to avoid a clash). Of course, perhaps this is a good thing if it stops people using unsafe functions like(Data.Map.!)
:)