Haskell中的C样式枚举?
在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
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]