以下代码抛出运行时异常并不奇怪:
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来局部禁用部分初始化记录的警告?
答案 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 Int
与Necklace
同构,因此在最简单的情况下几乎没有增加(除了访问Maybe
可能不存在的Necklace
的大量常用函数}})。如果您使Necklace
更复杂,那么get_necklace_id
就有意义了。
对于较大的项目,可以使用模板Haskell或额外的工具自动创建上面的get_necklace_id
。
更新:使用fromJust
并不是一个特别好的主意。要获得“合理的默认值”和“无失败模式”,您可以将get_necklace_id :: Necklace -> Maybe Int
与Data.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, ... }