【问题标题】:Constraint: Two type variables can be used with an operator约束:两个类型变量可以与一个运算符一起使用
【发布时间】:2013-12-24 06:20:06
【问题描述】:

我有以下函数编译运行成功:

-- 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 Floatb 类型为Velocity Float

【问题讨论】:

  • linearInterp 推断出什么类型?您可以在 ghci 中使用 :t 或在 ghc 中使用 -fwarn-missing-signatures 进行检查。
  • 其实是我自己做的——请看下面我的回答。

标签: haskell functional-programming


【解决方案1】:

如果我将您的代码包装在维度 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 类型类实际上会告诉编译器对不同类型进行算术运算,因为它们是 多参数 类:它们每个都采用 三个参数分别代表左参数类型、右参数类型和结果类型。

【讨论】:

  • 谢谢。但我想知道是否可以向 linearInterp 添加类型声明,以简化阅读并帮助诊断程序员错误。我似乎找不到不会产生编译器错误的类型声明。错误总是沿着“无法在表达式 a / b 中匹配 a 到 b”
  • 您可以准确地添加推断的类型(也许将类型变量重命名为更具描述性)-您希望更简单的东西吗?
  • 啊,我明白你的意思了。谢谢!
猜你喜欢
  • 2019-10-02
  • 1970-01-01
  • 2017-11-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-03
相关资源
最近更新 更多