如何使用限定名称处理看起来丑陋的中缀符号

hug*_*omg 10 haskell namespaces module operators

我通常坚信在我编程的大多数语言中都使用命名空间(合格的模块名称),因为一目了然地知道某个标识符的来源是非常好的.在Haskell中,还有一个额外的优点,即避免使用Prelude函数进行常见的名称冲突.

但是,我觉得必须在中缀符号(或其他简短的DSL-y标识符)上放置名称空间看起来很奇怪,所以我很想重新出口值,如下所示:

import qualified Data.Sequence as Seq
(|>) = (Seq.|>)
(<|) = (Seq.<|)
Run Code Online (Sandbox Code Playgroud)

现在困扰我的是那个

  • 手动重新出口的价值感觉就像无聊的样板.

  • 手动重新导出的值绕过现有的模块系统,似乎不适用于数据构造函数(可能还有其他我未遇到过的东西)

    import qualified Data.Sequence as Seq
    (:>) = (Seq.:>)  --gives me a parse error:
                     --"Not in scope: data constructor `:>'"
    
    Run Code Online (Sandbox Code Playgroud)

如何协调中缀符号和命名空间?我应该放弃并学会命名一切吗?是否有关于命名空间和符号的Haskell最佳实践?

Tik*_*vis 19

好吧,你可以做的一件事就是导入两次:

import Data.Sequence ((|>), (<|), ViewR ((:>)))
import qualified Data.Sequence as Seq
Run Code Online (Sandbox Code Playgroud)

这将只导入:>,|>以及<|不合格,留下一切合格.需要注意的是,因为:>是数据的构造函数,你也必须导入它的数据类型(ViewR),但你不能有进口的,其余ViewR的构造.

此外,如果您担心冲突,您应该只是隐藏运营商:

import Prelude hiding ((.))
Run Code Online (Sandbox Code Playgroud)

如果你正在使用一个理智的库,与Prelude的冲突意味着库函数被设计为替换 Prelude函数(例如Control.Category),所以你想让它替换默认含义.

就最佳实践而言,我从未见过任何人使用合格的运营商,除非发生冲突或他们在GHCi.总而言之,即使考虑到了解运营商所在位置的优势,也会使代码的可读性降低.


ehi*_*ird 8

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

import Data.Sequence (Seq, ViewL(..), ViewR(..), (|>), (<|))
import qualified Data.Sequence as Seq
Run Code Online (Sandbox Code Playgroud)

Data.Map和其他标准容器的文档建议使用这种双重导入的非限定类型名称样式.

尽管如此,您仍然无法始终导入不合格的运算符 - 例如,如果您使用Array/ Vector并且Map在同一模块中,则无法(!)从两个非资格中导入.在那种情况下,我通常只使用它合格.它看起来很奇怪,但它比其他选项更好(比如为其中一个提出你自己的名字以避免冲突).当然,如果它阻止人们使用不安全的功能,也许这是一件好事(Data.Map.!):)