有没有一种方法可以重写此函数?

时间:2019-05-23 16:42:04

标签: haskell functional-programming

我有一个函数,如下所示,Code Review上的某人建议我重写此函数。他们建议可以将对getRow(!)的调用替换为对zipfold的调用。

我已经考虑了这一点,但我真的看不到如何用这种方式重写它,也没有很好地了解如何教自己如何重写它。

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调用将失败。

1 个答案:

答案 0 :(得分:6)

如果索引超出范围,您可以使用safeGetRow :: Matrix a -> Maybe (Vector a)来返回Nothing

当然,问题是如果索引超出范围,我们该怎么办。两种合理的选择是:

  1. 使用Maybe [Int]代替[Int]作为返回类型并返回Nothing;或
  2. 返回一个空列表,因为如果该节点不在邻接矩阵中,那么它就没有neignbors。

例如,我们可以将其实现为:

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)
相关问题