2014-02-13 3 views
3

Я пытаюсь узнать у меня Haskell, и я решил практиковать, написав простую функцию для инвертирования матриц 3x3. Это должно быть легко, но я ничего не попытаюсь скомпилировать.Функция охранников и синтаксис «где» в Haskell

Вот мой код:

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 задано). Я уверен, что есть простейшая, фундаментальная вещь, которую мне не хватает. Может кто-нибудь указать, что я сделал не так?

UPDATE:

Я реализовал исправления, предложенные в комментариях, а также исправил выгружена индексы ошибку, которую я сделал (не заметил его раньше, так как код не скомпилируется). Вот фиксированный код, который переворачивает 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']] 
+0

Нет ошибки на линии, которую вы упомянули при компиляции, возможно, ваш отступ в вашем редакторе отличается от этого? С другой стороны, вы не можете указывать имена переменных, начинающиеся с заглавных букв - 'A',' B' .. 'I' - все недопустимы. Вы можете сделать '_A'. – user2407038

+0

Haskell чувствителен к белому пространству. Предложение 'where' выглядит подозрительным для меня, я бы поставил его, по крайней мере, на три пространства. – crockeea

+0

У меня была «таблетка» вместо четырех пробелов, которая невидимо прикручивала ее. Я исправил это, а также использовал _A, как вы предложили. Теперь функция работает так, как ожидалось. Спасибо за совет! – user2790167

ответ

1

Хорошее упражнение было бы обобщить эту функцию на произвольные -матрица. Вот один из способов расчета детерминанта 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 
Смежные вопросы