【问题标题】:Haskell code won't compile with certain variable namesHaskell 代码无法使用某些变量名进行编译
【发布时间】:2020-08-03 16:58:18
【问题描述】:

我从 GHCi 收到一个我无法解释的错误。我正在使用以下代码(其中绝大多数似乎与问题无关,但我无法用更少的代码复制问题;注释掉的行是我想添加以替换虚拟的行in 0 行)

import Linear
apply x f = f x
pos xs = -- smallest i where xs!!i > 0, else length xs
    let aux xs n = case xs of
                   x:t -> if x > 0 then n
                          else aux t (n+1)
                   [] -> n
    in aux xs 0
optimize d opt d_opt funs d_funs x0 p0 eps =
    let n = length funs in
    let aux x p f_best = let feas = map (apply x) funs in
                         let i = pos feas in
                         let (g,a,f_best) =
                                 if i == n then
                                    let g = d_opt x in
                                    let g' = p !* g in
                                    let prod = g `dot` g' in
                                    let g = g / (sqrt prod) in
                                    let f_best = min (opt x) f_best in
                                    let a = (opt x - f_best) / (sqrt prod) in
                                    (g,a,f_best)
                                 else
                                    let g = (d_funs!!i) x in
                                    let g' = p !* g in
                                    let prod = g `dot` g' in
                                    let g = g / (sqrt prod) in
                                    let a = ((funs!!i) x) / (sqrt prod) in
                                    (g,a,f_best)
                         in
                         let b = (1+d*a)/(d+1) in
                         let b' = 2/(1+a) in
                         let b'' = (1-a^2)*(d^2)/(d^2-1) in
                         let h = p !* g in
                         let y = x - b*g in
                         -- let q = (p - g'*(transpose g')*b*b')*b'' in
                         -- aux y q f_best
                         0
    -- in aux x0 p0 (1/0)
    in 0 

此代码导致 GHCi 抛出六个错误,包括突出显示 let h = p !* g in 中的 p;但是,当我将该行更改为 let g = p !* g in 时,它会通过。不幸的是,这样做然后取消注释下一行 (let x = x - b*g in) 会引发相同的错误(包括在同一位置突出显示 p)。

pp0 应该是使用 Linear 包的 (n×n) 方阵,而 gxx0 应该是 (n×1 ) 向量; d 是整数,opt 是 n 空间上的线性函数,funs 是 n 空间上的凸函数列表,d_optd_funs 是各自的梯度,eps 是实数.

任何帮助编译它都将不胜感激。谢谢!

编辑:这是错误消息之一。 let g = d_opt xlet f_best = min (opt x) f_bestlet g = (d_funs!!i) xlet a = ((funs!!i) x) / (sqrt prod)let b = (1+d*a)/(d+1) 也有类似的。

Lenstra.hs:57:34: error:
    • Occurs check: cannot construct the infinite type: a1 ~ m a1
      Expected type: m (m a1)
        Actual type: m (m (m a1))
    • In the first argument of ‘(!*)’, namely ‘p’
      In the expression: p !* g
      In an equation for ‘h’: h = p !* g
    • Relevant bindings include
        h :: m a1 (bound at Lenstra.hs:57:30)
        b'' :: m a1 (bound at Lenstra.hs:56:30)
        b' :: m a1 (bound at Lenstra.hs:55:30)
        b :: m a1 (bound at Lenstra.hs:54:30)
        g :: m a1 (bound at Lenstra.hs:37:31)
        a :: m a1 (bound at Lenstra.hs:37:33)
        aux :: m a1 -> m (m (m a1)) -> p8 -> p9 (bound at Lenstra.hs:35:9)
        (Some bindings suppressed; use -fmax-relevant-binds=N or -fno-max-relevant-binds)
   |
57 |                          let h = p !* g in
   |                                  ^
Failed, no modules loaded.

【问题讨论】:

  • 这可能意味着pq 的类型不同。
  • 甚至没有阅读问题:let x = x - b*g 定义 x 本身,而不是您可能想要的一些以前可用的 x。为新的x 选择一个新名称并相应地修改您的代码。 p 相同。 95% 相信您的问题会消失。
  • 但是这个算法太混乱了,无法有效调试。通常,您将逻辑拆分为执行特定任务的小部分。 let ... in ... 链接的数量是巨大的。虽然有 2-3 个 let 语句并不罕见,但上面的语句看起来并不像 Haskellish。事实上,它看起来也很程序化。
  • @DanielWagner 不幸的是,我尝试将名称更改为 let h = p !* glet y = x - b*h(保持 p 的重新定义被注释掉)并且似乎有相同的编译问题
  • @WillemVanOnsem 是的,我希望我有更少的链接,但是替换所有东西会使调试变得更加困难。是否更好?将if/else 的每个分支都粘贴到optimize 之外的自己的函数中?

标签: haskell haskell-linear


【解决方案1】:

有几个错误:

  • 其中整数d用作浮点数时,需要使用fromIntegral,例如:b = (1 + fromIntegral d * a)/(fromIntegral d + 1)
  • 向量和矩阵的标量乘法/除法不能使用*/。向量必须使用*^^*^/ 运算符,矩阵必须使用!!*!!/
  • 向量和矩阵的逐点求和和差不能使用+-。向量必须使用 ^+^^-^,矩阵必须使用 !+!!-!
  • 对于矢量g'transpose g' 不起作用,所以g' * transpose g' 没有祈祷。使用outer g' g'g' 的乘积得到的矩阵作为列向量,g' 作为行向量,如果这是你想要做的。
  • 在定义q 的范围内没有g'。也许您想从您的 if 语句中返回 g'
  • let g = some expression with g 不起作用,因为您将创建一个永远循环的递归定义。您需要使用一个新变量——您在某些地方正确地做到了这一点,但在其他地方却没有。

还有一个严重的逻辑错误,至少在您的注释语句未注释的版本中。函数aux 永远不会返回除了对aux 的尾调用之外的任何内容,因此它必然会永远循环。我什至不知道它应该返回什么类型。您需要一些停止条件(可能返回 f_best 或其他内容)。

您会发现将类型签名添加到optimize 及其aux 函数以控制这些错误很有帮助。以下类型检查但仍包含几个错误(无限循环等):

import Linear
import Data.Vector (Vector)

apply x f = f x

pos :: (Ord a, Num a) => [a] -> Int
pos xs = -- smallest i where xs!!i > 0, else length xs
    let aux xs n = case xs of
                   x:t -> if x > 0 then n
                          else aux t (n+1)
                   [] -> n
    in aux xs 0

type Matrix a = Vector (Vector a)

optimize
  :: Integer
  -> (Vector Double -> Double)
  -> (Vector Double -> Vector Double)
  -> [Vector Double -> Double]
  -> [Vector Double -> Vector Double]
  -> Vector Double
  -> Matrix Double
  -> Double
  -> a
optimize d opt d_opt funs d_funs x0 p0 eps =
    let n = length funs in
    let aux
          :: Vector Double
          -> Matrix Double
          -> Double
          -> a
        aux x p f_best = let feas = map (apply x) funs in
                         let i = pos feas in
                         let g :: Vector Double
                             (g,g',a,f_best) =
                                 if i == n then
                                    let g = d_opt x in
                                    let g' = p !* g in
                                    let prod = g `dot` g' in
                                    let g = g ^/ (sqrt prod) in  -- **LOOP**
                                    let f_best = min (opt x) f_best in
                                    let a = (opt x - f_best) / (sqrt prod) in
                                    (g,g',a,f_best)
                                 else
                                    let g = (d_funs!!i) x in
                                    let g' = p !* g in
                                    let prod = g `dot` g' in
                                    let g = g ^/ (sqrt prod) in  -- **LOOP**
                                    let a = ((funs!!i) x) / (sqrt prod) in
                                    (g,g',a,f_best)
                         in
                         let b = (1+fromIntegral d*a)/(fromIntegral d+1) in
                         let b' = 2/(1+a) in
                         let b'' = (1-a^2)*(fromIntegral d^2)/(fromIntegral d^2-1) in
                         let h = p !* g in
                         let y = x ^-^ b*^g in
                         let q = (p !-! outer g' g' !!* (b*b')) !!* b'' in
                         aux y q f_best
    in aux x0 p0 (1/0)

最后,当您运行此程序时,您可能希望将其提交给Code Review Stack Exchange,并附上算法说明和一些运行示例。我认为有很多风格上的改进可以使它更加地道。

【讨论】:

  • 非常感谢您如此彻底地查看代码。是的,outer 正是我想要做的。 q的定义应该引用了g,而不是g';这是先前调试尝试的产物。在尝试/尝试调试之前我没有开始编写的方法的唯一部分是停止条件,我计划将其放置在 i 的定义之后,它将返回 x(或转到另一个迭代)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-10-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-16
相关资源
最近更新 更多