简体   繁体   English

Haskell记录字段依赖性

[英]Haskell Record Field Dependency

data MyRecord = MyRecord {
  numberOfSides :: Int,
  shape :: Shape
}

Shape can be Triangle, Quadrilateral etc. depending on numberOfSides . Shape可以是三角形,四边形等,具体取决于numberOfSides

My question is: Those two fields are related. 我的问题是:这两个领域是相关的。 Is there a "trigger" mechanism to update the other when one field is updated? 当一个字段更新时,是否有“触发”机制来更新另一个? and if the two fields are in conflict then report a type error? 如果两个字段冲突,那么报告类型错误?

Another related scenario: 另一个相关场景:

data MyRecord = MyRecord {
  players      :: [Player],
  numOfPlayers :: Int
}

I want to somehow automatically calculate numberOfPlayers based on the size of players . 我想以某种方式根据players的大小自动计算numberOfPlayers

PS: Is this somehow related to GADT and dependant types ? PS:这是否与GADT依赖类型有关

In Haskell, unlike in OO languages, you can't modify a field in place. 在Haskell中,与OO语言不同,您无法在适当的位置修改字段。 So the usual approach, which is what I think you're thinking of, of having an explicit "setter" doesn't make sense in Haskell. 因此,通常的方法,即我认为你正在考虑的,有一个明确的“setter”在Haskell中没有意义。 The easiest thing, and this is well in line with the DRY principle (which is very relevant in functional languages as well as OO languages), is to only store one of the fields and have the other be an accessor, as mentioned in a comment. 最简单的事情,这很符合DRY原则 (在函数式语言和OO语言中非常相关),只是存储其中一个字段而另一个是访问者,如评论中所述。

-- deriving (...) clauses and other boilerplate omitted for brevity

data Shape = Triangle | Quad | Pentagon | Other

data MyRecord = MyRecord Int

numSides :: Shape -> Int
numSides Triangle = 3
numSides Quad = 4
numSides Pentagon = 5
numSides Other = 0

shape :: Int -> Shape
shape 3 = Triangle
shape 4 = Quad
shape 5 = Pentagon
shape _ = Other

makeMyRecord :: Shape -> MyRecord
makeMyRecord = MyRecord . numSides

numberOfSides :: MyRecord -> Int
numberOfSides (MyRecord x) = x

shapeOf :: MyRecord -> Shape
shapeOf = shape . numberOfSides

Now, Shape can be Enum and Bounded , if you haven't done that already. 现在, Shape可以是EnumBounded ,如果你还没有这样做的话。 From there, shape and numSides can be shortened in terms of the automatically generated Enum instance. 从那里,可以根据自动生成的Enum实例缩短shapenumSides If you want to be able to construct MyRecord from Int , you can either export the data constructor or define another makeMyRecord' to do it. 如果您希望能够从Int构造MyRecord ,您可以导出数据构造函数或定义另一个makeMyRecord'来执行它。 And now, since we're using the DRY principle, you can just let users update the field freely and the other "field" will magically be updated. 现在,由于我们正在使用DRY原则,您可以让用户自由更新字段,另一个“字段”将会神奇地更新。

My question is: Those two fields are related. 我的问题是:这两个领域是相关的。 Is there a "trigger" mechanism to update the other when one field is updated? 当一个字段更新时,是否有“触发”机制来更新另一个? and if the two fields are in conflict then report a type error? 如果两个字段冲突,那么报告类型错误?

PS: Is this somehow related to GADT and dependant types? PS:这是否与GADT和依赖类型有关?

This is related to dependent types, but not GADTs. 这与依赖类型有关,但与GADT无关。 Since this is Haskell, I would suggest simply storing the number of sides in the record and then writing a function numTypes :: Int -> Shape . 由于这是Haskell,我建议只需在记录中存储边数,然后编写函数numTypes :: Int -> Shape

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM