如何修复Haskell中的Monomorphism Restriction警告?
解决单态限制警告与签名冲突问题
问题根源
你遇到的矛盾核心在于:
- 单态限制(Monomorphism Restriction)要求无显式类型签名的绑定默认推断为单态类型
- 你尝试添加的
Integral i => i是多态类型签名,这与单态限制的规则直接冲突
好在你已经开启了ScopedTypeVariables扩展,可直接利用它复用外部定义的类型变量,避免重复约束。
标准解决方案
修改内部绑定的类型签名,直接复用pfactor中定义的类型变量i,无需重复添加Integral i =>约束:
{-# OPTIONS_GHC -Wall -fno-warn-incomplete-patterns #-} {-# LANGUAGE ExplicitForAll, ScopedTypeVariables #-} pfactor :: forall i. Integral i => i -> [(i, i)] pfactor m = pf' m [] $ primesUpTo (floorSqrt m) where pf' :: i -> [(i, i)] -> [i] -> [(i, i)] -- 复用外部的i,无需重复Integral约束 pf' n res (p : ps) | pIsNotAFactor = pf' n res ps | otherwise = pf' nDividedByPExp ((p, pexp) : res) remainingPrimes where (nDividedByP, r) = n `quotRem` p pIsNotAFactor = r /= 0 nDividedByPExp, pexp :: i -- 直接指定为外部的i类型 (nDividedByPExp, pexp) = getPExp' nDividedByP 1 getPExp' :: i -> i -> (i, i) -- 同样复用i getPExp' currNDividedByP currExp | pDoesNotDivideCurrNDividedByP = (currNDividedByP, currExp) | otherwise = getPExp' q1 (currExp + 1) where q1, r1 :: i -- 复用i (q1, r1) = currNDividedByP `quotRem` p pDoesNotDivideCurrNDividedByP = r1 /= 0 remainingPrimes = takeWhile (<= floorSqrt nDividedByPExp) ps floorSqrt :: Integral i => i -> i floorSqrt = undefined primesUpTo :: Integral i => i -> [i] primesUpTo = undefined
快速替代方案:关闭单态限制
如果不想调整类型签名,直接添加扩展关闭单态限制即可:
{-# OPTIONS_GHC -Wall -fno-warn-incomplete-patterns #-} {-# LANGUAGE ExplicitForAll, ScopedTypeVariables, NoMonomorphismRestriction #-}
但这种方法可能导致部分场景下的性能问题(比如意外的多态重复计算),建议优先使用第一种方案。
内容的提问来源于stack exchange,提问作者George Co
相关产品推荐
相关产品推荐

