【问题标题】:Is there a way to rewrite this function to be total?有没有办法将这个函数重写为全部?
【发布时间】:2019-10-10 06:59:15
【问题描述】:

我有一个函数,如下所示,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

此代码 sn-p 在我的程序上下文中工作,但如果 n 大于 (ncols mat) - 1 则某些 row ! m 调用将失败。

【问题讨论】:

  • 您可以使用safeGetRow :: Matrix a -> Maybe (Vector a)。如果n“超出范围”,Qustion 是您想要做的。

标签: haskell functional-programming


【解决方案1】:

您可以使用safeGetRow :: Matrix a -> Maybe (Vector a),它会在索引超出范围时返回Nothing

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

  1. 使用Maybe [Int]而不是[Int]作为返回类型并返回一个Nothing;或
  2. 返回一个空列表,因为如果节点不在邻接矩阵中,则它没有邻居。

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

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 -&gt; [a] 来防止使用(!) :: Vector a -&gt; Int -&gt; a看起来不安全:您使用了正确的索引,但这需要一些推理,而toList 是一个总函数,因此显然总会产生结果。

我们可以通过使用findIndices :: (a -&gt; Bool) -&gt; Vector a -&gt; 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 -&gt; (a -&gt; b) -&gt; Maybe a -&gt; 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)

【讨论】:

  • 你会选择哪个选项?在其他情况下做出此类决定时,您会权衡哪些因素?我想我在这里赞成“返回一个空列表”的想法,但我很好奇在其他情况下如何做到这一点。
  • @lachrimae:我个人会使用带有Maybe 的那个,因为那时结果有额外的数据:毕竟“索引超出范围”和没有的行之间存在差异Trues,但那当然更多的是“个人品味”。
  • 这是一个liquid haskell 也可以很好的时刻,因为如果程序编写正确,您将永远不会遇到超出范围的条件,因此它更像是编译时不变量。不过,我认为你必须做一些工作才能让 Matrix 进入它的大脑。 @lachrimae
  • Haskellers 是否采用 Liquid Haskell 作为“标准工具”,或者他们是否在特殊情况下使用它?它看起来很酷,我想知道这是否应该成为我实践的核心。
猜你喜欢
  • 2020-12-17
  • 2019-09-10
  • 1970-01-01
  • 2021-06-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-07
相关资源
最近更新 更多