haskell - 如何在 Haskell 中处理大量常量?

标签 haskell constants pattern-synonyms

我正在开发一个库,允许开发人员控制 Minitel(法国
可 View 文终端)。

我有很多不变的值(value)观,我想知道管理的最佳方式
他们与 Haskell。这是初学者的常见问题,但我还没有找到
满意的回答。

You can have a look at my project
(注意:是的,只有一个模块中有太多常量,这就是我正在研究的;-))

我目前有模块将它们保存为 name = value .虽然有效,但我
想知道它是否可以完善或我做得对。

aNUL = 0x00 -- Null
-- ...
aUS  = 0x1f -- Unit Separator

这种方法有个小缺点:不能使用模式匹配,需要
如果要保留名称,请使用 guard :
completeReturn :: MString -> Bool
completeReturn []                 = False
completeReturn [0x19]             = False -- eSS2
completeReturn [0x1b, 0x5b, 0x32] = False -- eESC, eCSI, 0x32
completeReturn [0x1b, 0x5b, 0x34] = False -- eESC, eCSI, 0x34
completeReturn [0x19, 0x4b]       = False -- eSS2, 0x4b ; cedilla
completeReturn _                  = True

如果您不希望 GHC 对您大喊大叫,您还必须使用 GHC 选项
缺少签名或类型默认值:
{-# OPTIONS_GHC -fno-warn-missing-signatures -fno-warn-type-defaults #-}

我曾经尝试过 data deriving Enum使用技巧来弥补
未定义的值,但一旦值不从 0 开始,它就会变得丑陋。
它也容易出错,如果您省略或添加一个值,以下名称将
使它们的值加或减一:
data ASCII = NUL -- ^ 0x00, Null
           -- ... 
           | US  -- ^ 0x1f, Unit Separator
           deriving (Enum, Show, Eq, Ord)

data C0 = NUL   -- ^ 0x00, NULl
        | Res01 -- ^ 0x01, undefined value
        -- ...
        | APA   -- ^ 0x1f, Activate Position Address
        deriving (Enum, Show, Eq, Ord)

data SSCFS = Res00 | Res01 | Res02 | Res03 | Res04 | Res05 | Res06 | Res07
           -- ...
           | Res38 | Res39 | Res3A | Res3B | Res3C | Res3D | Res3E | Res3F
           | ABK -- ^ 0x40, Alpha BlacK
           -- ...
           | RMS -- ^ 0x5f
           deriving (Enum, Show, Eq, Ord)

此解决方案有一个缺点:您无法轻松混合列表中的值
因为它们是不同的类型:
codes = [ASCII.NUL, ASCII.SOH, C0.APB, C0.APF, 0x24] -- Error!

我想到了另一个解决方案:
class Value a where
    value :: a -> Int

-- ASCII codes
data ASCII = NUL | SOH | STX | ETX {- ... -} deriving Show

instance Value ASCII where
    value NUL = 0
    value SOH = 1
    -- ...

-- C0 codes
data C0 = APB | APF | APD | APU {- ... -} deriving Show

instance Value C0 where
    value APB = 10
    value APF = 11
    -- ...

-- Mini type
data Mini = ASCII ASCII | C0 C0 | Literal Int deriving Show

instance Value Mini where
    value (ASCII code)  = value code
    value (C0 code)     = value code
    value (Literal int) = int

codes = [ASCII NUL, C0 APB, Literal 0x20]

main = do
    print (fmap value codes)

对于这个解决方案,我必须注意构造函数不要重叠。为了
例如,NUL、SO 和 SI 在 ASCII 和 C0 中都存在(幸运的是,它们给出了
相同的值:-))。我可以通过仅在 ASCII 中定义它们来处理这种情况
例子。使用合格的导入会使事情变得更丑陋( ASCII ASCII.NUL )。

你有没有其他更好的方法来处理这个案子?

最佳答案

如果你有 ghc 7.8,一个新的语言扩展 pattern synonyms (参见第 7.3.8 节)优雅地解决了这个问题。使用 LANGUAGE pragma 启用模式同义词或 -XPatternSynonyms旗帜。

{-# LANGUAGE PatternSynonyms #-}

模式同义词定义以 pattern 为前缀
pattern NUL = 0x00
pattern SSC = 0x19
pattern ESC = 0x1b
pattern US  = 0x1f
pattern CSI = 0x5b

我们可以根据这些模式编写您的示例。
type MString = [Int]

completeReturn :: MString -> Bool
completeReturn []                 = False
completeReturn [SSC]              = False -- eSS2
completeReturn [ESC , CSI , 0x32] = False -- eESC, eCSI, 0x32
completeReturn [ESC , CSI , 0x34] = False -- eESC, eCSI, 0x34
completeReturn [SSC , 0x4b]       = False -- eSS2, 0x4b ; cedilla
completeReturn _                  = True

模式同义词是双向的,因此我们也可以使用它们来构造表达式。
completeReturn [SSC]

您可以编写捕获变量的模式同义词。
pattern EscCsi x = [ESC , CSI , x]

并将它们用作模式匹配的构造函数
completeReturn :: MString -> Bool
completeReturn []                 = False
completeReturn [SSC]              = False -- eSS2
completeReturn (EscCsi 0x32)      = False -- eESC, eCSI, 0x32
completeReturn (EscCsi 0x34)      = False -- eESC, eCSI, 0x34
completeReturn [SSC , 0x4b]       = False -- eSS2, 0x4b ; cedilla
completeReturn _                  = True

并用于构造表达式。
completeReturn (EscCsi 0x7e)

关于haskell - 如何在 Haskell 中处理大量常量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28659903/

相关文章:

java - 从Java调用Haskell,动态链接错误重定位

parsing - haskell 中的暂停点何时应该与额外的 "space"一起使用?

haskell - 简单数据类型的未装箱向量

c++ - C++ 中的复合类型、const 和 auto

Haskell 字节串 : How to pattern match?

haskell - 消化函数和 listOf

c - 为什么在使用 typedef 时非 const 指针被视为 const?

c++ - const 是谎言吗? (因为 const 可以被抛弃)

haskell - 我怎样才能写出这个模式同义词而没有歧义的类型错误?

haskell - 编写模式同义词来隐藏构造函数