Haskell中的C样式枚举?

Haskell中的C样式枚举?,haskell,enums,Haskell,Enums,在C中,我们用以下方式定义枚举: enum E { E0, E1, E2 = 3, E3 }; 注意E2=3表达式,枚举类型导致E0==0,E1==1,E2==3,E3==4 在Haskell中,我们无法在声明中指定枚举。实现不连续枚举的唯一方法是手动实现Enum类 有什么方便的方法吗 我已经使用Haskell编写了一个模板来生成Enum实例 data E = E0 | E1 | E2_3 | E3 der

在C中,我们用以下方式定义枚举:

enum E {
    E0,
    E1,
    E2 = 3,
    E3
};
注意
E2=3
表达式,枚举类型导致
E0==0,E1==1,E2==3,E3==4

在Haskell中,我们无法在声明中指定枚举。实现不连续枚举的唯一方法是手动实现
Enum

有什么方便的方法吗

我已经使用Haskell编写了一个模板来生成
Enum
实例

data E = E0
       | E1
       | E2_3
       | E3
       deriving Show

enum ''E

我想知道是否有库试图填补这一空白?

您可以使用Template Haskell的
reifyAnnotations
功能创建一些小而简单的东西

首先,我们需要定义一个注释类型来保存枚举值:

{-# LANGUAGE DeriveDataTypeable #-}
module Def where

import Data.Data

data EnumValue = EnumValue Int deriving (Typeable, Data)
其次,我们需要一些代码来使用这些注释,并将它们转换为
Enum
实例定义:

{-# LANGUAGE TemplateHaskell, QuasiQuotes #-}
module TH where

import Def
import Language.Haskell.TH.Syntax
import Language.Haskell.TH
import Control.Monad
import Data.List (mapAccumL)
import Data.Maybe

enumValues :: [(a, Maybe Int)] -> [(a, Int)]
enumValues = snd . mapAccumL (\next (x, mv) -> let v = fromMaybe next mv in (v+1, (x, v))) 0

enumFromAnns :: Name -> Q [Dec]
enumFromAnns name = do
    TyConI (DataD _ _ _ cons _) <- reify name
    eVals <- fmap enumValues $ forM cons $ \(NormalC conName []) -> do
        anns <- reifyAnnotations (AnnLookupName conName)
        let ev = case anns of
                [EnumValue ev] -> Just ev
                [] -> Nothing
        return (conName, ev)
    [d|
     instance Enum $(conT name) where
       fromEnum = $(lamCaseE [match (conP c []) (normalB $ lift v) [] | (c, v) <- eVals])
       toEnum =  $(lamCaseE [match (litP . IntegerL . fromIntegral $ v) (normalB $ conE c) [] | (c, v) <- eVals])|]
用法示例:


你想解决什么潜在问题?@Franky,我正在解析一个二进制文件,它是由C语言编写的程序生成的。@wenlong:你能用c2hs生成枚举类型吗?
{-# LANGUAGE TemplateHaskell #-}
module AnnotatedEnumExample where

import Def
import TH

data E = E1
       | E2
       | E42
       | E43
       deriving Show

{-# ANN E1 (EnumValue 1) #-}
{-# ANN E42 (EnumValue 42) #-}

-- Force new declaration group
return []

enumFromAnns ''E
*AnnotatedEnumExample> map fromEnum [E1, E2, E42, E43]
[1,2,42,43]
*AnnotatedEnumExample> map toEnum [1, 2, 42, 43] :: [E]
[E1,E2,E42,E43]