Alternative to algebraic data type with lots of constructors in record syntax

Lor*_*nzo 2 haskell record algebraic-data-types

I have a custom data type to contain elements of a landscape (cloud, sun, mountain, etc). I need to have a list of them, so I can't use different types and a common typeclass.

They share most of the fields in the constructor, however some have properties that other don't (for example, if the cloud is raining or not).

As of now, I have one data type with different constructors:

data Element = Sun {
  elemColorStart :: Color,
  elemColorEnd :: Color,
  elemCoords :: Coords,
  elemPeriod :: Float,
  elemSize :: Float,
  elemSteps :: Step,
  elemTime :: Float
}
| Cloud {
  elemKind :: CloudKind,
  elemColorMain :: Color,
  elemCoords :: Coords,
  elemRans :: [Float],
  elemSize' :: Size',
  elemSteps :: Step,
  elemTime :: Float
}
... etc
Run Code Online (Sandbox Code Playgroud)

Alternatively I could have a common constructor with all the possible properties, and just not initialise them if theyre not needed, though this looks even worse.

This does not look very "Haskelly", and in fact this approach in general is quite object oriented. What am I doing wrong? Any other possible approach would be welcome; it is not an assignment so I don't really have any constraints.

Nik*_*kov 9

Isolate the things into their own datatypes and have Element be a sum of them:

data Sun = Sun {
  colorStart :: Color,
  colorEnd :: Color,
  coords :: Coords,
  period :: Float,
  size :: Float,
  steps :: Step,
  time :: Float
}

data Cloud = Cloud {
  kind :: CloudKind,
  colorMain :: Color,
  coords :: Coords,
  rans :: [Float],
  size :: Size',
  steps :: Step,
  time :: Float
}

data Element = SunElement Sun | CloudElement Cloud
Run Code Online (Sandbox Code Playgroud)

Now you can have dedicated APIs for things in isolation as much as all the good things that come with separation of concerns.

Oh and BTW, I've dropped the prefixes on field names, since now we have the DuplicateRecordFields extension.

BTW, you'll find this question useful.

  • @Lorenzo如果不想污染名称空间,则需要使用前缀(如您所愿),或者在单独的模块中定义它们,然后将合格的MyModule导入为M,然后使用M.field。后者并不十分方便,我认为如果要在模块中添加很多类型就可以了。 (3认同)