haskell - Haskell:使用 List Monad 计算周期
问题描述
-- 1. Graph structure: nodes and adjacency matrix (i.e. the edges)
data Node = A | B | C | D | E | F deriving (Show,Eq,Ord)
adj :: (Node,Node) -> Bool
adj p = case p of
(A,B) -> True
(A,C) -> True
(B,C) -> True
(B,F) -> True
(C,D) -> True
(D,E) -> True
(E,B) -> True
(E,F) -> True
(F,A) -> True
(_,_) -> False
type Path = [Node]
-- 2. Auxiliary functions
adjacentNodes :: Node -> [Node] -> [Node]
adjacentNodes n ns = filter (\x -> adj(n,x)) ns
allNodes :: [Node]
allNodes = [A,B,C,D,E,F]
choice :: ([a],[a]) -> [a]
choice = uncurry (++)
-- 3. To do
addtoEnd :: Path -> [Node] -> [Path]
addtoEnd p ns = undefined
hCycles :: Node -> [Path]
hCycles n = undefined
我有这个代码(它是给我们的,我不能改变它或类型)并且需要hCycles
使用 list monad(和 do 表示法)定义函数。hCycles
应该为图像中图形的任何通用节点计算哈密顿循环。
问题是我不太确定如何使用 list monad 来做到这一点......尽管如此,我认为我有该函数的第一个版本:
hCycles :: Node -> [Path]
hCycles n = do
p <- [[n]]
nextNode <- adjacentNodes n allNodes
if n == nextNode
then [p]
else addtoEnd p allNodes
仍然 if/else 情况有一个奇怪的行为,因为hCycles
没有再次调用,我什至不认为它是递归的......我该如何解决这个问题?
解决方案
在 list monad 中的一行:
x <- f y
期望f
返回一个列表。x
将依次使用列表的每个值进行实例化,因此该do
子句的其余部分将使用这些值中的每一个运行。
您将看到它adjacentNodes
返回一个节点列表。因此,从您开始,n
您可以像这样考虑它连接到的每个节点:
nextNode <- adjacentNode n allNodes
编写这个函数:
steps :: [Nodes] -> Path -> [Path]
steps _ [] = fail "Need a node to start with."
steps ns path@(n:rest) = do
nextNode <- adjacentNode n ns
guard $ not $ elem nextNode path -- Stop if we've already visited this node.
return $ nextNode : path
您可以将其想象为查找单个路径的算法,该算法(感谢 list monad)神奇地找到所有可能的路径。这不是完整的答案,但它应该给你足够的开始。
(注意:我还没有实际测试过这段代码。)
推荐阅读
- android-layout - Android studio 3.3 Go to Declaration 不起作用
- dart - 在类中定义类——比如java
- node.js - NestJS 初创公司的开发速度令人难以置信
- excel - Excel 更新通知 - Lotus Notes
- java - 什么事件会使等待线程执行另一个线程已经运行的同步方法?
- java - 根据 url 的 request.body 输出创建字典,然后在 VF 页面中打印
- java - 从@ExceptionHandler 重定向不起作用
- google-apps-script - Google表格:如何找到每列的最后一行?
- java - 通过自定义按钮将数据从 JDialog 传递到框架
- sql-server - 如何在 SQL Server 中将 try_convert 与可为空的字段进行比较