Better Way to Define an Enum in Haskell

前端 未结 5 619
囚心锁ツ
囚心锁ツ 2021-02-01 01:48

I want a datatype to represent a finite set of integers that can be addressed by specific names. I figure the best way to do that is to use an Enum.

However, there is o

5条回答
  •  清歌不尽
    2021-02-01 01:58

    The problem with the accepted solution is the compiler won't tell you when you are missing an enum in your table. The deriving Enum solution is great, but it won't work if you want to have an arbitrary mapping to numbers. Another answer suggests Generics or Template Haskell. This follows up on that by using Data.

    {-# Language DeriveDataTypeable #-}
    import Data.Data
    data MyDataType = Foo | Bar | Baz deriving (Eq, Show, Data, Typeable)
    
    toNumber enum = case enum of
       Foo -> 1
       Bar -> 2
       Baz -> 4
    

    We will get compiler warning in the toNumber case mapping when a new constructor is added.

    Now we just need the ability to turn that code into data so that the mapping can be automatically reversed. Here we generate the same table mentioned in the accepted solution.

    table = map (\cData -> let c = (fromConstr cData :: MyDataType) in (c, toNumber c) )
          $ dataTypeConstrs $ dataTypeOf Foo
    

    You can fill out an Enum class just the same as in the accepted answer. Unmentioned there is that you can also fill out the Bounded class.

提交回复
热议问题