ADT - 构造函数和类型 - 函数只接受其中一个构造函数

时间:2014-06-15 17:15:33

标签: haskell

我写了hsexif库,我现在要添加一个功能,但我不确定如何准备API。

我有ExifValue类型。 ExifValue可以是ExifRational,它具有分子和分母。通常,您希望将该值(显示)显示为" num / den",例如,对于1/160的展示时间。 但是,有时您希望将其显示为浮点数,例如曝光补偿,您将显示为" -0.75"例如,或光圈(" 6.3")。

所以我想添加一个函数:

formatAsFloatingPoint :: ExifValue -> Int -> String

该函数采用exif值和逗号后的浮点数在结果字符串中输出,并返回格式化的字符串。

然而,该函数将接受任何ExifValue,如果它将ExifText作为该函数的参数提供,则用户将收到运行时错误并且没有编译时警告...

在这种情况下,我如何制作干净且类型安全的API?

1 个答案:

答案 0 :(得分:4)

您需要考虑如何使用它。

来电者可能始终知道他们有ExifRational,并且只会使用此类值调用formatAsFloatingPoint。在这种情况下,重构数据类型是有意义的:

data Rational = Rational !Int !Int

data ExifValue = ... | ExifRational Rational | ...

(或者可能重用一些现有的类型来表达理性)

然后让formatAsFloatingPoint获取Rational

formatAsFloatingPoint :: Rational -> Int -> String

这会将责任移交给调用者以决定何时调用它。

或者,也许调用者只想显示任意ExifValue,但如果值恰好是ExifRational,则会有特殊行为。在这种情况下,只需使用一个包罗万象的案例,例如:

formatAsFloatingPoint :: ExifValue -> Int -> String
formatAsFloatingPoint n (ExifRational num den) = ...
formatAsFloatingPoint _ v = show v

有更复杂的方法基于使用类型参数来标记您拥有的是什么类型的东西,但这将涉及重构整个库,并且这里有必要的证据。如果你想在代码库中遇到一个更普遍的问题,想要表明你有特定种类的ExifValue,那么它们可能是有意义的。