Haskell linear库构建希尔伯特矩阵报Could not deduce (Dim n0)错误求解
问题背景
想要使用linear库构建希尔伯特矩阵,并将其转换为嵌套列表,该任务被类型级约束阻碍,原始实现代码如下:
import Linear import Linear.V import Data.Vector qualified as V -- | Outer (tensor) product of two vectors outerWith :: (Functor f, Functor g, Num a) => (a -> a -> a) -> f a -> g a -> f (g a) {-# INLINABLE outerWith #-} outerWith f a b = fmap (\x -> fmap (f x) b) a hilbertV :: forall a n. (Fractional a, Dim n) => Integer -> V n (V n a) hilbertV n = let v = V $ V.fromList $ fromIntegral <$> [1..n] w = V $ V.fromList $ fromIntegral <$> [0..n-1] in luInv $ outerWith (+) w v listsFromM :: V n (V n a) -> [[a]] listsFromM m = vToList (vToList <$> m) vToList :: V n a -> [a] vToList = V.toList . toVector hilbertL :: forall a. (Fractional a) => Integer -> [[a]] hilbertL n = listsFromM (hilbertV n)
编写最后一行hilbertL n = listsFromM (hilbertV n)时触发编译错误:
bench/Solve.hs:28:26: error: • Could not deduce (Dim n0) arising from a use of ‘hilbertV’ from the context: Fractional a bound by the type signature for: hilbertL :: forall a. Fractional a => Integer -> [[a]] at bench/Solve.hs:27:1-56 The type variable ‘n0’ is ambiguous These potential instances exist: three instances involving out-of-scope types instance GHC.TypeNats.KnownNat n => Dim n -- Defined in ‘Linear.V’ instance Data.Reflection.Reifies s Int => Dim (Linear.V.ReifiedDim s) -- Defined in ‘Linear.V’ instance forall k (n :: k) a. Dim n => Dim (V n a) -- Defined in ‘Linear.V’ • In the first argument of ‘listsFromM’, namely ‘(hilbertV n)’ In the expression: listsFromM (hilbertV n) In an equation for ‘hilbertL’: hilbertL n = listsFromM (hilbertV n)
错误原因
错误核心是层级不匹配:
V n (V n a)中的n是类型级维度参数,Dim n是操作该类型必须的编译期约束,要求维度在编译阶段可确定hilbertL接收的是运行时传入的Integer类型维度值,直接调用hilbertV时,编译器无法推断出隐式类型级n对应的具体类型,因此抛出模糊类型变量n0的错误。
修复方案
使用linear库内置的运行时维度反射函数reifyDim,将运行时传入的整数值临时提升为满足Dim n约束的类型级维度,在反射作用域内完成矩阵构建和转换即可。
步骤1:补充必要导入
需要从Linear.V导入反射相关的函数和类型,导入部分修改为:
import Linear import Linear.V (Dim(..), V(..), reifyDim, toVector, Proxy(..)) import Data.Vector qualified as V
步骤2:修改hilbertL实现
通过reifyDim反射运行时维度,在回调作用域内调用矩阵构建和转换逻辑:
hilbertL :: forall a. Fractional a => Integer -> [[a]] hilbertL n | n <= 0 = [] -- 处理非法维度输入 | otherwise = reifyDim (fromInteger n) \(_ :: Proxy n) -> listsFromM (hilbertV n :: V n (V n a))
可选优化
原始hilbertV重复接收了词法级的维度参数,在Dim n约束下可以直接通过类型类拿到对应维度值,无需额外传参,优化后代码更简洁:
hilbertV :: forall a n. (Fractional a, Dim n) => V n (V n a) hilbertV = let n = fromIntegral $ dim (Proxy :: Proxy n) v = V $ V.fromList $ fromIntegral <$> [1..n] w = V $ V.fromList $ fromIntegral <$> [0..n-1] in luInv $ outerWith (+) w v -- 对应hilbertL的调用可同步简化 hilbertL n | n <= 0 = [] | otherwise = reifyDim (fromInteger n) \(_ :: Proxy n) -> listsFromM (hilbertV :: V n (V n a))
内容的提问来源于stack exchange,提问作者tkx68
相关产品推荐
相关产品推荐

