如何处理带有限定名称的丑陋中缀符号

发布于 2024-12-29 11:08:37 字数 627 浏览 0 评论 0原文

我通常坚信在我编程的大多数语言中使用命名空间(限定模块名称),因为一眼就知道某个标识符来自哪里是非常好的。在 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

花开雨落又逢春i 2025-01-05 11:08:37

那么,您可以做的一件事就是导入它两次:

import Data.Sequence ((|>), (<|), ViewR ((:>)))
import qualified Data.Sequence as Seq

这将仅导入 :>|><| 不合格的,让其他一切都合格。请注意,由于 :> 是数据构造函数,因此您还必须导入其数据类型 (ViewR),但您不必导入 ViewR 的其余构造函数。

此外,如果您担心冲突,则应该适当隐藏该运算符:

import Prelude hiding ((.))

如果您使用的是正常的库,则与 Prelude 的冲突意味着该库函数旨在替换该 Prelude 函数(例如Control.Category)所以你想让它取代默认的含义。

就最佳实践而言,我从未见过有人使用合格的操作员,除非存在冲突或他们在 GHCi。总而言之,即使考虑到知道操作符来自哪里的优势,它也会使代码的可读性大大降低。

Well, one thing you can do is import it twice:

import Data.Sequence ((|>), (<|), ViewR ((:>)))
import qualified Data.Sequence as Seq

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 of ViewR's constructors.

Additionally, if you're worried about conflicts, you should just hide the operator as appropriate:

import Prelude hiding ((.))

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.

相思碎 2025-01-05 11:08:37

我通常导入类型名称、不合格的构造函数和运算符,以及其他所有合格的内容:

import Data.Sequence (Seq, ViewL(..), ViewR(..), (|>), (<|))
import qualified Data.Sequence as Seq

Data.Map 和其他标准容器。

不过,您不能总是导入不合格的运算符 - 例如,如果您在同一模块中使用 Array/VectorMap,您无法从两个不合格的对象中导入 (!)。在这种情况下,我通常只会使用它。它看起来很奇怪,但它比其他选项更好(比如为其中一个选择你自己的名字以避免冲突)。当然,如果它阻止人们使用像 (Data.Map.!) 这样的不安全函数,也许这是一件好事:)

I generally import the type names, constructors and operators unqualified, and everything else qualified:

import Data.Sequence (Seq, ViewL(..), ViewR(..), (|>), (<|))
import qualified Data.Sequence as Seq

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 and Map 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.!) :)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文