这是其中一种情况,为了避免输入错误,您需要能够同时通过专有名称引用整个参数及其子组件。
幸运的是,Haskell 提供了这一点。这被称为“as 模式”。更多细节在这里:SO-q30326249。
在您的情况下,您可以将图形参数记为:g@(Graph(pairs))。那么g就是你的graph对象,pairs就是[(Vertex,OutNeighbors)]类型对应的列表。
你没有告诉我们你的contains函数,但可以推断它的类型是:
contains :: Vertex -> Graph -> Bool
考虑到这一点,您的图形函数的版本可以采用任意迭代计数:
type Vertex = Int
type OutNeighbors = [Vertex]
data Graph = Graph [(Vertex,OutNeighbors)] deriving (Eq, Show, Read)
funcN :: Int -> Graph -> Graph
funcN iterCount g@(Graph(pairs)) =
if (iterCount <= 0) then g -- nothing to do
else let
gm1 = funcN (iterCount - 1) g -- recursion
fn = \(v,ngs) -> contains v gm1 -- filtration
in
Graph (filter fn pairs)
使用相同的技术,contains 函数的暂定版本可能是这样的:
contains :: Vertex -> Graph -> Bool
contains v g@( Graph [] ) = False
contains v g@( Graph ((v0,ngs0):pairs) ) = (v == v0) || contains v (Graph(pairs))
第二个函数有点复杂,因为列表可以通过 2 种模式来描述,空的和非空的。
最后,可以像这样编写恰好执行 10 次迭代的函数版本:
func10 :: Graph -> Graph
func10 g = funcN 10 g
或者以更简洁的方式使用部分应用程序(在 Haskell 圈子中称为 currying):
func10 :: Graph -> Graph
func10 = funcN 10
附录:库样式,使用nest:
如果由于某种原因“手动递归”不受欢迎,可以使用 nest :: Int -> (a -> a) -> a -> a 库函数来代替。它在内部使用递归计算函数的第 N 次组合幂。
然后只需要编写图函数的单次迭代版本。代码如下所示:
import Data.Function.HT (nest)
funcNl :: Int -> Graph -> Graph
funcNl iterCount g0 = let
-- 2 local function definitions:
ftfn g1 (v, ngs) = contains v g1
func1 g2@(Graph(pairs)) = Graph (filter (ftfn g2) pairs)
in
nest iterCount func1 g0