我有一个函数,如下所示,Code Review上的某人建议我重写此函数。他们建议可以将对getRow
和(!)
的调用替换为对zip
或fold
的调用。
我已经考虑了这一点,但我真的看不到如何用这种方式重写它,也没有很好地了解如何教自己如何重写它。
import Data.Matrix (Matrix, getRow, ncols)
import Data.Vector ((!))
type AdjacencyMatrix = Matrix Bool
-- Input: the graph's adjacency matrix and a vertex.
-- Output: the list of neighbours of that vertex.
neighbours :: AdjacencyMatrix -> Int -> [Int]
neighbours mat n = filter (\m -> row ! m) [0..(ncols mat)-1]
where row = getRow n mat
此代码段在我的程序上下文中起作用,但是如果n
大于(ncols mat) - 1
,则某些row ! m
调用将失败。
答案 0 :(得分:6)
如果索引超出范围,您可以使用safeGetRow :: Matrix a -> Maybe (Vector a)
来返回Nothing
。
当然,问题是如果索引超出范围,我们该怎么办。两种合理的选择是:
Maybe [Int]
代替[Int]
作为返回类型并返回Nothing
;或例如,我们可以将其实现为:
import Data.Matrix(Matrix, safeGetRow)
import Data.Vector(toList)
neighbours :: AdjacencyMatrix -> Int -> Maybe [Int]
neighbours mat n = map fst . filter snd . zip [0..] . toList <$> safeGetRow n mat
我们在这里使用toList :: Vector a -> [a]
来防止使用{em>看起来不安全的(!) :: Vector a -> Int -> a
:您使用了正确的索引,但这需要一些推理,而toList
是全部功能,因此很明显总是会产生结果。
我们可以使用findIndices :: (a -> Bool) -> Vector a -> Vector Int
使它更紧凑:
import Data.Matrix(Matrix, safeGetRow)
import Data.Vector(findIndices, toList)
neighbours :: AdjacencyMatrix -> Int -> Maybe [Int]
neighbours mat n = toList . findIndices id <$> safeGetRow n mat
或者我们可以使用maybe :: b -> (a -> b) -> Maybe a -> b
来使用一个空列表:
import Data.Matrix(Matrix, safeGetRow)
import Data.Maybe(maybe)
import Data.Vector(findIndices, toList)
neighbours :: AdjacencyMatrix -> Int -> [Int]
neighbours mat n = maybe [] (toList . findIndices id) (safeGetRow n mat)