Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell ADT—构造函数和类型—只接受一个构造函数的函数_Haskell - Fatal编程技术网

Haskell ADT—构造函数和类型—只接受一个构造函数的函数

Haskell ADT—构造函数和类型—只接受一个构造函数的函数,haskell,Haskell,我编写了这个库,现在我要添加一个特性,但我不确定如何准备API 我有这个型号。ExifValue可以是ExifRational,它有一个分子和一个分母。通常,您希望将该值显示为num/den,例如显示时间为1/160。 但是,有时您希望将其显示为浮点数,例如,用于曝光补偿(例如,显示为-0.75)或光圈6.3 所以我想添加一个函数: formatAsFloatingPoint :: ExifValue -> Int -> String 该函数在结果字符串中输出exif值和逗号后的浮

我编写了这个库,现在我要添加一个特性,但我不确定如何准备API

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

所以我想添加一个函数:

formatAsFloatingPoint :: ExifValue -> Int -> String
该函数在结果字符串中输出exif值和逗号后的浮点数,并返回格式化字符串

但是,如果函数将ExifText作为该函数的参数,那么该函数将接受任何ExifValue,并且用户将得到运行时错误和编译时警告


在这种情况下,如何创建一个干净且类型安全的API?

您需要考虑如何使用它

调用者可能总是知道他们有一个Exiferational,并且只会使用这样的值调用formatAsFloatingPoint。在这种情况下,重构数据类型是有意义的:

data Rational = Rational !Int !Int

data ExifValue = ... | ExifRational Rational | ...
或者可能重用某些现有类型来表示有理数

然后将formatAsFloatingPoint设置为有理数:

这将责任转移到调用方来决定何时调用它

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

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

有一些更复杂的方法是基于使用类型参数来标记您所拥有的内容,但这将涉及重构整个库,这里没有什么证据可以证明这一点。如果您在代码库中遇到了一个更普遍的问题,即希望发出信号表明您具有特定类型的ExifValue,那么它们可能是有意义的。

您需要考虑如何使用它

调用者可能总是知道他们有一个Exiferational,并且只会使用这样的值调用formatAsFloatingPoint。在这种情况下,重构数据类型是有意义的:

data Rational = Rational !Int !Int

data ExifValue = ... | ExifRational Rational | ...
或者可能重用某些现有类型来表示有理数

然后将formatAsFloatingPoint设置为有理数:

这将责任转移到调用方来决定何时调用它

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

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

有一些更复杂的方法是基于使用类型参数来标记您所拥有的内容,但这将涉及重构整个库,这里没有什么证据可以证明这一点。如果您在代码库中遇到了一个更普遍的问题,即希望发出信号表示您有特定类型的ExifValue,那么它们可能是有意义的。

是的,既然您这样说,那么第一个选项可能是正确的前进方向。。更重要的是,我有另一个构造函数ExirationalList![Int,Int],它可能成为ExiFractionalList[Rational]。不过,这可能会让用户代码更加冗长。需要考虑一下。ExiFractionalList也可能是第二个选项的一个参数-您可以在定义中使用另一种情况来识别它并将整个列表格式化为浮点。在EXIF中,会出现一个有理列表,例如GPS坐标。我不认为将rational列表打印成string是常见的用例,我认为用户代码会有特殊的要求。我认为,打印出基本类型并让您处理复合大小写的方法更明智。好吧,也许我会选择第二种方法,因为函数并不是您每天都要做的事情,可能仅仅为了这个目的包装类型是过度的。第二种解决方案也有道理,因为您提到的其他原因。我想我会选择第二种解决方案。谢谢是的,既然你这么说了,第一个选择可能是正确的前进方向。。更重要的是,我有另一个构造函数ExirationalList![Int,Int],它可能成为ExiFractionalList[Rational]。不过,这可能会让用户代码更加冗长。需要考虑一下。ExiFractionalList也可能是第二个选项的一个参数-您可以在定义中使用另一种情况来识别它并将整个列表格式化为浮点。在EXIF中,会出现一个有理列表,例如GPS坐标。我不认为将rational列表打印成string是常见的用例,我认为用户代码会有特殊的要求。我认为,打印出基类型并让您处理复合情况的方法更为合理。好吧,也许我会选择第二个选项,因为函数不是真正的东西 你每天都这么做,可能只是为了这个目的而包装字体太过分了。第二种解决方案也有道理,因为您提到的其他原因。我想我会选择第二种解决方案。谢谢