Haskell中的记录getter是否有默认值?

时间:2012-01-25 13:49:47

标签: haskell record algebraic-data-types

以下代码抛出运行时异常并不奇怪:

data Necklace = InvalidNecklace |
    Necklace { necklace_id :: Int, meow :: Int, ... }
necklace_id InvalidNecklace

在应用于necklace_id以获取值而不是抛出异常时,是否有一些自然的方法可以为InvalidNecklace定义值?

如果我尝试了显而易见的事情,GHC会因为'necklace_id'的多次声明错误而失败:

necklace_id InvalidNecklace = -1

是否有一些pragma可以告诉GHC用这个声明取代它的推断声明?

我可以通过添加InvalidNecklace来声明{ necklace_id :: Int }是一个记录,但是我不能保证它总是返回-1,并且通常会造成可怕的混乱。我可以简单地定义:

get_necklace_id InvalidNecklace = -1
get_necklace_id x = necklace_id x

但这部分地违背了记录的目的。

我想通过编写:

可以创建一个特殊的invalidNecklace
invalidNecklace = Necklace { necklace_id = -1,
     meow = error "meow invalidNecklace accessed", ... }

第二种方法有什么缺点吗?我当然失去了使meow严格或解压缩的能力,但也许可以保持单独的调试和优化版本。是否有一个pragma来局部禁用部分初始化记录的警告?

2 个答案:

答案 0 :(得分:8)

(更新如下)

如您所见,无法进一步定义Necklace声明定义的getter。没有改变它的pragma。

Haskell的常见做法是使用这种风格:

get_necklace_id :: Necklace -> Maybe Int
get_necklace_id InvalidNecklace = Nothing
get_necklace_id (Necklace x) = Just x

使用魔术返回值“-1”是具有更简单类型系统的C类语言的常见样式。但请注意Maybe IntNecklace同构,因此在最简单的情况下几乎没有增加(除了访问Maybe可能不存在的Necklace的大量常用函数}})。如果您使Necklace更复杂,那么get_necklace_id就有意义了。

对于较大的项目,可以使用模板Haskell或额外的工具自动创建上面的get_necklace_id

更新:使用fromJust并不是一个特别好的主意。要获得“合理的默认值”和“无失败模式”,您可以将get_necklace_id :: Necklace -> Maybe IntData.Maybe.fromMaybe :: a -> Maybe a -> a(常见的可能处理函数之一)组合成这样:

from_necklace_id :: Int -> Necklace -> Int
from_necklace_id default = fromMaybe default . get_necklace_id

a_necklace_id :: Necklace -> Int
a_necklace_id = from_necklace_id (-1)

a_necklace_id与使用(-1)替换InvalidNecklace的函数相同。需要不同默认值的代码可以使用from_necklace_id

答案 1 :(得分:4)

为什么你不能拥有类型项链只代表有效的项链,而项链可能是项链可能无效?或者,避免使用Maybe,类似的东西(请注意,我仍然不确定这里有什么好的命名约定):

data Necklace = InvalidNecklace | NecklaceData NecklaceData
data NecklaceData = NecklaceDataRec { necklace_id :: Int, meow :: Int, ... }