输入值的签名

时间:2013-04-11 05:27:20

标签: haskell

我挣扎了好几个小时才得到类似下面的内容:

to_xyz_regular :: (RealFrac t) => (RegularSpd t) -> (t, t, t)
to_xyz_regular spd@(RegularSpd lambda_min lambda_max spectrum delta inverse_delta) =  
    let
        l = length cie_x - 1
        il = 1.0 / fromIntegral l
        samp i = sample spd $ lambda_min + inverse_delta * fromIntegral i
        integrate curve = (foldr (+) 0 $
                           map (\i -> curve!!i * samp i) [0..l]) * il
    in (integrate cie_x, integrate cie_y, integrate cie_z)

(这是从颜色SPD /光谱到XYZ颜色的转换例程。)

cie_XXX的定义如下:

cie_start = 360.0
cie_end = 830.0
cie_x = [0.0001299000, 0.0001458470, 0.0001638021, 0.0001840037,
         ....]
cie_y = ....
cie_z = ....

然后给我粗略的

Could not deduce (t ~ Double)
from the context (RealFrac t)
....

问题是cie_XXX值存储为Double,我真的希望它们是poylmorphic。

我最终找到的解决方案是为这些值添加类型签名:

cie_start :: (RealFrac t) => t
cie_end :: (RealFrac t) => t
cie_x :: (RealFrac t) => [t]
cie_y :: (RealFrac t) => [t]
cie_z :: (RealFrac t) => [t]

现在我的问题是:这是在Haskell中使用多态值/文字的正确方法吗?


在网络搜索上找到解决方案对我来说有点困难,因为书籍,教程等仅提及参数函数的类型签名 - >值只是无参数函数吗?

1 个答案:

答案 0 :(得分:4)

您选择的方式是在Haskell中为数字文字提供多态类型的正确方法。

Double类型选择cie_XXX的原因是由于Haskell的默认机制(更详细地描述了here)。当一个其他多态类型(包含forall,无论是隐式还是显式)需要由monomorphism restriction 单态时类型是不明确的(包含类型变量)时调用默认值仅显示在=>左侧的内容,例如a中的(Read a, Show a) => String该类型被限制为Prelude的实例或标准库定义的Num子类。默认强制将类型与default (...)中的每个条目统一(从最左边的条目开始),直到统一成功。默认default (...)

default (Integer, Double)

如果由于某种原因Float是实数的理想默认值,

default (Integer, Float)

可以定义。如果Float是所有数字的所需默认值,

default (Float)

可以定义。

在原始方案的情况下,

cie_start :: Fractional a => a

cie_start(以及cie_end)的最常规类型。推断出此类型会违反monomorphism restriction。但是,在存在默认情况下,首先尝试使用类型变量a的几种类型。鉴于默认default (...)default (Integer, Double)IntegerDouble将按此顺序进行尝试。

cie_start :: Fractional Integer => Integer

导致违反约束(Integer不是Fractional的实例)。

cie_start :: Fractional Double => Double

成功,并简化为

cie_start :: Double

要使原始方案成为错误而不是默认为Double(并且还完全禁用默认),请添加

default ()

位于定义cie_XXX的模块的顶层。

要使方案不需要显式类型签名,而是推断最常规类型,请添加

{-# LANGUAGE NoMonomorphismRestriction #-}

到定义cie_XXX的模块顶部(有关默认情况下未使用此最常用类型的原因的更多详细信息,请参阅Monomorphism restriction。)

总的来说,您选择解决此问题的方法(添加显式类型签名)是最佳解决方案。在所有顶级定义上都有类型签名被认为是最佳实践。