Haskell自定义运算符中缀属性及相关语法问题咨询
关于Haskell多元多项式库的几个问题
我开发了一个可处理多元多项式的Haskell库,该库依赖numeric-prelude库定义的加法群实例,但该实例的+与数字原生+冲突,因此我定义了:
import Algebra.Additive as AlgAdd (^+^) :: Polynomial a -> Polynomial a -> Polynomial a (^+^) p q = p AlgAdd.+ q
但我担心这样会丢失原+的中缀属性,现提出以下问题:
问题1:原库代码中有infixl 6 +, -,是否需在我的代码开头添加infixl 6 ^+^, ^-^?在函数前定义中缀属性是否为等价写法?能否通过(^+^) = (AlgAdd.+)自动继承中缀属性?
- 必须手动添加
infixl 6 ^+^, ^-^。Haskell中运算符的固定性(优先级、结合性)是绑定在名称上的,不会随函数值的赋值自动继承,所以显式声明是必要的。 - 在函数前写
infixl声明和单独定义是完全等价的,比如:
和先定义infixl 6 ^+^ (^+^) :: Polynomial a -> Polynomial a -> Polynomial a (^+^) = AlgAdd.+infixl再写函数实现效果一致。 - 不能通过
(^+^) = (AlgAdd.+)自动继承中缀属性。固定性属于运算符名称本身,不是函数的逻辑实现,所以即使赋值,新运算符也不会自动获得原运算符的优先级和结合性。
问题2:代码中的{-# MINIMAL zero, (+), ((-) | negate) #-}是什么含义?
这是Haskell的最小化实例编译指示,用于类型类定义中,明确实现该类型类实例时的最低要求:
- 要么实现
zero、(+)、(-)三个核心方法; - 要么实现
zero、(+)、negate(因为减法x - y可以通过x + negate y推导出来)。
编译器会根据这个指示检查实例是否满足要求,避免遗漏必要的核心逻辑。
问题3:我已定义多项式减法p ^-^ q,如何定义多项式的相反数^-^ p?
Haskell允许运算符重载,只要通过类型签名区分前缀和中缀用法即可:
infixl 6 ^+^, ^-^ -- 可选:前缀运算符通常优先级更高,比如设为infix 8,也可保持和减法一致 infix 6 ^-^ -- 中缀减法 (^-^) :: Polynomial a -> Polynomial a -> Polynomial a p ^-^ q = p AlgAdd.+ AlgAdd.negate q -- 前缀相反数 (^-^) :: Polynomial a -> Polynomial a (^-^) = AlgAdd.negate
调用时直接写^-^ p,编译器会根据类型推断识别这是前缀用法。如果觉得同符号容易混淆,也可以改用-^这类单独的前缀运算符,可读性会更好。
问题4:原库定义Double实例时使用的INLINE编译指示有什么作用?
INLINE是GHC的优化编译指示,核心作用有两点:
- 强制内联展开:告诉编译器在调用该函数的位置,直接替换函数代码,而非生成函数调用指令,减少小函数(比如数值类型的基础运算)的调用开销。
- 支持跨模块优化:默认GHC不会对跨模块调用的函数做内联,
INLINE会暴露函数代码给调用模块,让编译器在全局范围内做优化,比如消除冗余计算、合并操作等。
对于多项式运算这类频繁调用数值方法的场景,INLINE能显著提升运行性能。
内容的提问来源于stack exchange,提问作者Stéphane Laurent
相关产品推荐
相关产品推荐

