如何使用折叠重写此 haskell 函数?
How to rewrite this haskell function using folds?
我写了一个haskell函数来计算矩阵的行列式:
determinant :: Matrix -> Int
determinant [] = 0
determinant [[k]] = k
determinant n = sum [((-1) ^ m) * (head n !! m) * determinant (removeColumn (drop 1 n) m) | m <- [0 .. l]]
where
l = length (head n) - 1
它使用辅助函数'removeColumn'提取列:
removeColumn :: Matrix -> Int -> Matrix
removeColumn m n = map (\row -> take (n-1) row ++ drop n row) m
我想尝试使用折叠重写“行列式”函数。我已经集思广益了一段时间,但我想不出如何开始。任何帮助将不胜感激。
很难在不从根本上改变它的情况下转换你的版本,因为它使用了不规则的递归方案。对于折叠,您希望您的函数具有这样的基本结构,用于某些 z
和 k
:
determinant [] = z
determinant (x : xs) = k x (determinant xs)
您的函数在 determinant (removeColumn (drop 1 n) m)
上递归,因此显然不兼容。
我没有从你的函数开始,而是冒昧地编写了一个基于 the Leibniz formula from Wikipedia:
的实现
import Data.Bifunctor (first, bimap)
-- e.g. insertEverywhere 0 [1,2] == [(0,[0,1,2]),(1,[1,0,2]),(2,[1,2,0])]
-- the tupled integer keeps track of the number of inversions
insertEverywhere :: a -> [a] -> [(Int, [a])]
insertEverywhere x =
(\(ys,yss) -> (0,(x:ys)):yss)
. foldr
(\y (ys1,ys2) -> (y:ys1, (1, y:x:ys1):map (bimap (+ 1) (y:)) ys2))
([], [])
permutations :: [a] -> [(Int, [a])]
permutations =
foldr
(\x xs -> concatMap (\(n, xs) -> map (first (+ n)) (insertEverywhere x xs)) xs)
[(0, [])]
determinant :: Num a => [[a]] -> a
determinant =
sum
. map (\(i,p) -> (-1) ^ i * product (zipWith (!!) p [0..]))
. perms
我想说这个实现的重要部分是使用排列作为中间结构(与倒数相加)。
我写了一个haskell函数来计算矩阵的行列式:
determinant :: Matrix -> Int
determinant [] = 0
determinant [[k]] = k
determinant n = sum [((-1) ^ m) * (head n !! m) * determinant (removeColumn (drop 1 n) m) | m <- [0 .. l]]
where
l = length (head n) - 1
它使用辅助函数'removeColumn'提取列:
removeColumn :: Matrix -> Int -> Matrix
removeColumn m n = map (\row -> take (n-1) row ++ drop n row) m
我想尝试使用折叠重写“行列式”函数。我已经集思广益了一段时间,但我想不出如何开始。任何帮助将不胜感激。
很难在不从根本上改变它的情况下转换你的版本,因为它使用了不规则的递归方案。对于折叠,您希望您的函数具有这样的基本结构,用于某些 z
和 k
:
determinant [] = z
determinant (x : xs) = k x (determinant xs)
您的函数在 determinant (removeColumn (drop 1 n) m)
上递归,因此显然不兼容。
我没有从你的函数开始,而是冒昧地编写了一个基于 the Leibniz formula from Wikipedia:
的实现import Data.Bifunctor (first, bimap)
-- e.g. insertEverywhere 0 [1,2] == [(0,[0,1,2]),(1,[1,0,2]),(2,[1,2,0])]
-- the tupled integer keeps track of the number of inversions
insertEverywhere :: a -> [a] -> [(Int, [a])]
insertEverywhere x =
(\(ys,yss) -> (0,(x:ys)):yss)
. foldr
(\y (ys1,ys2) -> (y:ys1, (1, y:x:ys1):map (bimap (+ 1) (y:)) ys2))
([], [])
permutations :: [a] -> [(Int, [a])]
permutations =
foldr
(\x xs -> concatMap (\(n, xs) -> map (first (+ n)) (insertEverywhere x xs)) xs)
[(0, [])]
determinant :: Num a => [[a]] -> a
determinant =
sum
. map (\(i,p) -> (-1) ^ i * product (zipWith (!!) p [0..]))
. perms
我想说这个实现的重要部分是使用排列作为中间结构(与倒数相加)。