You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 04:18:20