Haskell中将Num类加法提升到动态值及时变点加法实现问题
问题原因
你遇到的类型错误核心原因有两个:
Num类实例定义不完整:Haskell内置Num类型类要求实现6个方法,你目前只实现了(+)、(-)、(*),缺少abs、signum、fromInteger,实例本身不合法。- 类型语义不匹配:
np1 + np2的返回值类型是Point (Moving Float),这是一个包含两个时变坐标字段的结构体,本身不是可接收时间参数的函数,你直接对它传入1.0作为参数时,编译器会误以为你要把一个Point值当Double -> t类型的函数调用,自然报类型不匹配错误。
修改步骤
所有修改均保留你现有代码结构,不做框架性调整,符合贴合原论文代码的要求:
1. 补全Moving v的Num实例
补全缺失的3个Num方法,让时变值的Num实例合法:
instance Num v => Num (Moving v) where (+) a b = \t -> (a t) + (b t) (-) a b = \t -> (a t) - (b t) (*) a b = \t -> (a t) * (b t) abs mf = \t -> abs (mf t) signum mf = \t -> signum (mf t) fromInteger n = const (fromInteger n)
2. 补全Point (Moving v)的Num实例
同样补全该实例缺失的3个Num方法:
instance Num v => Num (Point (Moving v)) where (+) a b = xy (x a + x b) (y a + y b) (-) a b = xy (x a - x b) (y a - y b) (*) a b = xy (x a * x b) (y a * y b) abs p = xy (abs $ x p) (abs $ y p) signum p = xy (signum $ x p) (signum $ y p) fromInteger n = xy (fromInteger n) (fromInteger n)
3. 新增时变点的时刻取值函数
新增辅助函数,用于给包含时变坐标的Point传入时间参数,获取对应时刻的静态点值:
atTime :: Point (Moving v) -> Time -> Point v atTime p t = xy (x p t) (y p t)
4. 修正测试代码写法
将原来直接对相加结果传时间参数的写法,改为用atTime取值:
-- 可正常运行的测试用例 testAddMP1 :: Point Float testAddMP1 = (np1 + np2) `atTime` 1.0 -- 计算结果为 Point 5.0 2.0,符合时变点加法预期
可选优化(更贴合时变语义)
如果你希望时变点本身就是Moving (Point v)类型(即Time -> Point v,和时变Float的结构完全统一),可以额外给静态Point v写Num实例,这样时变点会自动复用你之前写的Moving v的Num实例,不需要单独为Point (Moving v)写实例:
instance Num v => Num (Point v) where (+) a b = xy (x a + x b) (y a + y b) (-) a b = xy (x a - x b) (y a - y b) (*) a b = xy (x a * x b) (y a * y b) abs p = xy (abs $ x p) (abs $ y p) signum p = xy (signum $ x p) (signum $ y p) fromInteger n = xy (fromInteger n) (fromInteger n) -- 此时时变点类型为 Moving (Point Float),可以直接传时间参数 np1', np2' :: Moving (Point Float) np1' = \t -> xy (4.0 + 0.5 * t) (4.0 - 0.5 * t) np2' = \t -> xy (0.0 + 1.0 * t) (0.0 - 1.0 * t) -- 可以直接写 (np1' + np2') 1.0,不需要额外atTime函数 testAddMP1' = (np1' + np2') 1.0
内容的提问来源于stack exchange,提问作者Patrick Browne
相关产品推荐
相关产品推荐

