【问题标题】:Function guards & 'where' syntax in HaskellHaskell 中的函数保护和“where”语法
【发布时间】:2014-03-11 17:56:33
【问题描述】:

我正在尝试学习 Haskell,我决定通过编写一个简单的函数来反转 3x3 矩阵来练习。这应该很容易,但我尝试的任何方法都不会成功编译。

这是我的代码:

matInv3x3 :: [[Double]] -> [[Double]]
matInv3x3 m
    | length m /= 3         = error "wrong number of rows"
    | length (m !! 0) /= 3  = error "wrong number of elements in row 0"
    | length (m !! 1) /= 3  = error "wrong number of elements in row 1"
    | length (m !! 2) /= 3  = error "wrong number of elements in row 2"
    | det == 0              = error "zero determinant"
    | otherwise = mInv
    where   a = m !! 0 !! 0
            b = m !! 0 !! 1
            c = m !! 0 !! 2
            d = m !! 1 !! 0
            e = m !! 1 !! 1
            f = m !! 1 !! 2
            g = m !! 2 !! 0
            h = m !! 2 !! 1
            i = m !! 2 !! 2
            det = a*(e*i - f*h) - b*(i*d - f*g) + c*(d*h - e*g)
            A = (e*i - f*h) / det
            B = -(d*i - f*g) / det
            C = (d*h - e*g) / det
            D = -(b*i - c*h) / det
            E = (a*i - c*g) / det
            F = -(a*h - b*g) / det
            G = (b*f - c*e) / det
            H = -(a*f - c*d) / det
            I = (a*e - b*d) / det
            mInv = [[A,B,C],[D,E,F],[G,H,I]]

我正在努力防范所有可能出错的事情:错误的列表维度和零行列式。我根据“Learn You A...”一书中的示例对其进行建模。如果矩阵的行列式为零,我会尝试依赖惰性求值。

GHCi 不会编译它,引用第 10 行的“=”的解析错误(其中定义了 b)。我敢肯定,我缺少一些简单、基本的东西。谁能指出我做错了什么?

更新:

我实现了 cmets 中提出的修复,还纠正了我犯的交换索引错误(之前没有发现它,因为代码无法编译)。这是固定代码,它可以正确反转 3x3 矩阵:

matInv3x3 :: [[Double]] -> [[Double]]
matInv3x3 m
    | length m /= 3         = error "wrong number of rows"
    | length (m !! 0) /= 3  = error "wrong number of elements in row 0"
    | length (m !! 1) /= 3  = error "wrong number of elements in row 1"
    | length (m !! 2) /= 3  = error "wrong number of elements in row 2"
    | abs det < 1.0e-15     = error "zero or near-zero determinant"
    | otherwise = mInv
    where   [[a,d,g],[b,e,h],[c,f,i]] = m
            det = a*(e*i - f*h) - b*(i*d - f*g) + c*(d*h - e*g)
            a' = (e*i - f*h) / det
            b' = -(d*i - f*g) / det
            c' = (d*h - e*g) / det
            d' = -(b*i - c*h) / det
            e' = (a*i - c*g) / det
            f' = -(a*h - b*g) / det
            g' = (b*f - c*e) / det
            h' = -(a*f - c*d) / det
            i' = (a*e - b*d) / det
            mInv = [[a',b',c'],[d',e',f'],[g',h',i']]

【问题讨论】:

  • 我编译时你提到的那一行没有错误 - 也许你在编辑器中的缩进与这里不同?另一方面,您不能给出以大写字母开头的变量名称 - A,B .. I - 都是无效的。你可以做_A
  • Haskell 对空格敏感。 where 子句对我来说看起来很可疑,我至少可以将其放在至少三个空格中。
  • 这些值的常规名称是a'i'。 GHC 特别对待以_ 开头的值——如果它们未使用,它不会发出警告。我不建议这样命名。
  • 您可以在单行中分配所有矩阵元素[[a,d,g],[b,e,h],[c,f,i]] = m
  • @user2790167 你能把你的答案放在答案框中,而不是放在问题里吗?

标签: function haskell syntax where guard


【解决方案1】:

一个很好的练习是将这个函数推广到任意 nxn 矩阵。如果您有兴趣,这是一种计算 nxn 行列式的方法。

-- Remove the nth element from a list
remove :: Int -> [a] -> [a]
remove n xs = ys ++ (tail zs)
  where
    (ys, zs) = splitAt n xs

-- Minor matrix of cofactor C(i,j)
minor :: Int -> Int -> [[a]] -> [[a]]
minor i j xs = remove j $ map (remove i) xs

-- The determinant of a square matrix represented as a list of lists
-- representing column vectors, that is [column].
det :: Num a => [[a]] -> a
det (a:[]) = head a
det m = sum [(-1)^i * (c1 !! i) * det (minor i 0 m) | i <- [0 .. (n-1)]]
  where
    c1 = head m
    n = length m

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-03-25
    • 2016-05-18
    • 1970-01-01
    • 1970-01-01
    • 2011-01-09
    • 1970-01-01
    • 2011-10-10
    • 1970-01-01
    相关资源
    最近更新 更多