约束:两个类型变量可以与运算符一起使用

时间:2013-12-23 22:05:51

标签: haskell functional-programming

我有以下功能可以编译并成功运行:

-- Linearly interpolates between two values. That is, it is a function which:
--   returns y1 when x = x1
--   returns y2 when x = x2
--   returns a value between y1 and y2 when x1 < x < x2
linearInterp x1 y1 x2 y2 x =
  (x - x1) * slope + y1
  where slope = (y2 - y1) / (x2 - x1)

我想给它一个类型签名:

linearInterp :: a -> b -> a -> b -> a -> b

但是,正如预期的那样,类型签名会导致编译错误。那是因为编译器无法确定是否可以使用任意类型ab进行算术运算。例如。它不知道你可以将b除以a,就像我在slope的定义中所做的那样。

有没有办法写出类型约束,说“a / b是可能的,”“a + b是可能的,”等等?我见过MulDivSum类型类。但它们似乎并没有告诉编译器有关在两个不同类型上进行算术的事情。

如果你想知道,这对我很重要,因为我正在使用Dimensional包。确实可以对该包中的不同类型进行算术运算。例如,您可以拨打linearInterp,其中a类型为Length Float,类型bVelocity Float

1 个答案:

答案 0 :(得分:5)

如果我将代码包装在维度Prelude的导入中:

import Prelude ()
import Numeric.Units.Dimensional
import Numeric.Units.Dimensional.Prelude

linearInterp x1 y1 x2 y2 x =
  (x - x1) * slope + y1
  where slope = (y2 - y1) / (x2 - x1)

我推断出这种类型:

linearInterp
  :: (Fractional a, Mul d1 d' d, Div d d1 d') =>
     Dimensional DQuantity d1 a
     -> Dimensional DQuantity d a
     -> Dimensional DQuantity d1 a
     -> Dimensional DQuantity d a
     -> Quantity d1 a
     -> Quantity d a

如果你想要那种普遍性,这似乎是一个非常合理的函数类型。

MulDivSum类型实际上告诉编译器对不同类型进行算术运算,因为它们是多参数类:它们各自采用三个参数,表示左参数类型,右参数类型和结果类型。