关于记录全局命名空间的当前最佳实践

时间:2013-10-04 08:27:40

标签: haskell

我正在检查目前没有使用模板 - haskell /某些镜头的一些幻想来处理简单的情况:

data Person = Person {
  name :: String,
  ...
}

data Company = Company {
  name :: String,
  ...
}

目前我通过限定导入来避免污染全局命名空间,但它确实使记录访问变得笨拙。

import Person as P

isFred :: Person -> Bool
isFred p = (P.name p) == "Fred"

还有没有更好的方法来访问记录字段?


我接受了@Emmanuel Touzery的答案,因为有关同一理由的另一个问题的有用链接。另一个问题并没有显示在" haskell命名空间"上的搜索。其他答案没有错,但我只能接受其中一个。

那里提到的解决方案使用模板Haskell,镜头,类型等等基本上为每个字段创建一个类型类#34; HasName"使用单一功能" name"。然后,每个数据类型都是具有自己的实现的该类的实例。然后有一些魔法,我不完全理解允许涉及不同的类型。

对于任何想知道这是什么的Haskell新手来说,它是因为记录基本上是元组,其中字段选择器被实现为普通函数,选择(例如)该元组的第二个元素。如果你导出这些字段选择器函数,那么它们就会位于全局命名空间中,迟早(通常会更快)就会发生冲突。

所以 - 您要么对导入进行限定(如上面的示例所示),要么尝试提出不会发生冲突的名称(名称前缀并希望最好)。

截至2013年,镜头材料风靡一时,可以选择现场选择器/吸气器+定位器等。镜头的基本概念并不复杂,但实现方式正在我的脑海中。


对于记录(哈!)我认为另一篇文章中的解决方案可能就是我之后的问题,但它确实涉及大量的魔术(5个扩展仅用于假记录命名空间)。

3 个答案:

答案 0 :(得分:7)

一般来说,只有两种方法,但遗憾的是社区中没有关于它们的理由:

  1. 将包含函数的记录放在单独的文件中,并使用完全别名限定,如下所示:

    import qualified Data.Person as Person; import Data.Person (Person)
    
    isFred :: Person -> Bool
    isFred p = (Person.name p) == "Fred"
    

    考虑这种方法与Java这样的语言相同,其中文件只包含一个类。

  2. 将您的记录放在同一个文件中,同时在字段名称前加上记录名称,例如:

    data Person = Person {
      personName :: String,
      personAge :: Int,
      ...
    }
    
  3. 镜片库都没有解决这个问题。

答案 1 :(得分:2)

已经提出了类似的问题,你可以在这里看到一个答案: https://stackoverflow.com/a/17488365/516188

目前镜头是Haskell社区的一个流行词,他们肯定有自己的用途,而且它们可能是这个命名空间问题解决方案的一部分,长期存在。但是目前只使用镜头来解决这个问题的人我认为是少数。正如Nikita Volkov所说,合格的进口和前缀将是目前的典型解决方案。

更新:发现有关this other option但尚未最终确定但似乎很骄傲。这里在this blog post结束时提到。

答案 2 :(得分:0)

这是我的方法。在实践中,我发现我不经常需要导出记录名称,因此命名空间污染只是模块本身的一个问题。所以我使用短前缀,通常是类型类的第一个字母,如下所示:

data Person = Person {
  pName :: String,
  ...
}

data Company = Company {
  cName :: String,
  ...
}

在我需要允许其他模块直接访问字段的情况下,通常只有一个或两个字段。而且我经常只想允许读访问。所以在这种情况下,我可能会有点创意,也许就是这样。

module Whatever
  {
     Person,
     personName,
     Company,
     companyName,
     ...
   }

data Person = Person {
  pName :: String,
  ...
}

data Company = Company {
  cName :: String,
  ...
}

personName :: Person -> String
personName = pName

companyName :: Company -> String
companyName = cName