使用 Haskell 从列表传递闭包

2024-02-04

我需要使用 Haskell 在列表上生成传递闭包。

到目前为止我得到了这个:

import Data.List
qq [] = []
qq [x] = [x]
qq x = vv (sort x)

vv (x:xs) = [x] ++ (member [x] [xs]) ++  (qq xs)

member x [y] = [(x1, y2) | (x1, x2) <- x, (y1, y2) <- qq (y), x2 == y1]

输出1:

*Main> qq [(1,2),(2,3),(3,4)]
[(1,2),(1,3),(1,4),(2,3),(2,4),(3,4)]

输出2:

*Main> qq [(1,2),(2,3),(3,1)]
[(1,2),(1,3),(1,1),(2,3),(2,1),(3,1)]

问题出在第二个输出上。它不检查新生成的列表上是否有额外的传递闭包,而是仅返回结果。

为了原型化 Haskell 代码,我使用了这个Python代码:

def transitive_closure(angel):
    closure = set(angel)
    while True:
        new_relations = set((x,w) for x,y in closure for q,w in closure if q == y)
        closure_until_now = closure | new_relations    
        if closure_until_now == closure:
            break    
        closure = closure_until_now    
    return closure

print transitive_closure([(1,2),(2,3),(3,1)])

Output:

set([(1, 2), (3, 2), (1, 3), (3, 3), (3, 1), (2, 1), (2, 3), (2, 2), (1, 1)])

这是我的 Haskell 函数中需要的正确输出。

如何在我的 Haskell 代码中做同样的事情? (我需要重新创建if从 Python 代码到 Haskell 代码的语句)


我不完全确定你想在 Haskell 代码中做什么。相反,我们可以将 Python 代码移植到 Haskell。

为了简单起见,我们只使用列表而不涉及集合。如果您确实需要性能,那么使用集合并没有那么困难;然而,如果没有一些严肃的杂技,我们就无法在 Haskell 中使用集合推导式。如果我们不介意较慢的代码,我们可以使用nub² 获得与列表相同的效果。

我喜欢用类型签名开始编写函数;它让我更容易思考我正在实施的具体内容。我们正在获取一个对列表并生成另一个对列表。这意味着该类型将roughly be:

[(a, b)] → [(a, b)]

然而,我们希望能够将这些对的左右部分相互比较==。这意味着他们必须是same类型并且他们必须支持==。所以实际的类型是:

transitiveClosure ∷ Eq a ⇒ [(a, a)] → [(a, a)]

现在让我们看看您的实际算法。主要部分是while True环形。我们想将其转换为递归。考虑递归的最佳方法是将其分解为基本情况和递归情况。对于循环,这大致对应于停止条件和循环体。

那么基本情况是什么?在您的代码中,循环的退出条件隐藏在主体内部。我们停下来时closure_until_now == closure。 (巧合的是,这就是您在问题中提到的 if 语句。)

在函数定义中,我们可以指定这样的逻辑:guards,所以我们的递归函数的第一部分如下所示:

transitiveClosure closure 
  | closure == closureUntilNow = closure

这就像你的if陈述。当然,我们还没有定义closureUntilNow然而!那么接下来我们就这样做吧。这只是一个辅助变量,所以我们把它放在where函数定义之后的块。我们可以使用与 Python 代码中相同的理解方式来定义它:nub确保它保持唯一:

  where closureUntilNow = 
          nub $ closure ++  [(a, c) | (a, b) ← closure, (b', c) ← closure, b == b']

此代码的作用相当于 while 循环中的前两行。

最后,我们只需要递归案例。如果我们是这样,我们该怎么办not完成了吗?在你的while循环,你刚刚设置closure to closureUntilNow并再次迭代。我们将通过递归调用执行完全相同的操作:

  | otherwise = transitiveClosure closureUntilNow

由于这是模式保护的一部分,因此它会above the where堵塞。所以,把它们放在一起,我们得到:

transitiveClosure ∷ Eq a ⇒ [(a, a)] → [(a, a)]
transitiveClosure closure 
  | closure == closureUntilNow = closure
  | otherwise                  = transitiveClosure closureUntilNow
  where closureUntilNow = 
          nub $ closure ++ [(a, c) | (a, b) ← closure, (b', c) ← closure, b == b']

希望这能让编写这个程序的思路变得清晰。

¹这很困难,因为Set不形成Haskell Monad。它是更一般意义上的 monad,但它不符合 Prelude 中的类。所以我们不能只使用 monad 推导式。我们could使用具有可重新绑定语法的 monad 推导式来实现这一目标,但这并不值得。

²nub是一个名称愚蠢的函数,用于从列表中删除重复项。我认为 OCaml 的dedup is a much更好的名字。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 Haskell 从列表传递闭包 的相关文章

  • 在 Haskell 中等待然后检测按键的简单方法是什么?

    我对 Haskell 还很陌生 所以我正在寻找一种简单的方法来检测按键 而不是使用getLine 如果有人知道任何库 或者知道一些这样做的技巧 那就太好了 如果有更好的地方可以问这个问题 请直接告诉我 我将不胜感激 如果您不想阻止 可以使用
  • Haskell 单例:我们可以通过 SNat 获得什么

    我正在尝试使用 Haskell 单例 在论文中使用单例进行依赖类型编程 http cs brynmawr edu rae papers 2012 singletons paper pdf并在他的博客文章中单例 v0 9 发布 https t
  • 为什么 GeneralizedNewtypeDeriving 没有安全的 Haskell?

    来自 GHC 手册 第安全语言 http www haskell org ghc docs 7 6 2 html users guide safe haskell html safe language 模块边界控制 使用安全语言编译的 Ha
  • 副作用是纯函数中找不到的一切吗?

    可以肯定地说 以下二分法成立 每个给定的函数是 要么纯粹 或有副作用 如果是这样 函数的 副作用就是纯函数中找不到的任何东西 这很大程度上取决于您选择的定义 可以公平地说 函数是pure or impure 纯函数始终返回相同的结果并且不会
  • 如何将可选标志解析为 Maybe 值?

    我正在尝试使用optparse 应用程序 https hackage haskell org package optparse applicative 0 11 0 2解析一个Maybe String但我找不到任何地方如何处理Maybe 我
  • 表达式“ap zip tail”如何工作

    我想知道怎么写f x zip x tail x 点免费 所以我使用了pointfree程序 结果是f ap zip tail ap作为 Control Monad 的函数 我不明白点自由定义是如何工作的 如果我能从类型的角度去理解的话 希望
  • 如何向 Scotty 中间件添加基本身份验证?

    我目前正在制作 Scotty API 但找不到任何 basicAuth 实现的示例 Wai Middleware HttpAuth 具体来说 我想将基本身份验证标头 用户 通行证 添加到我的某些端点 即以 admin 开头的端点 我已经设置
  • Haskell 二进制解析

    我一直在尝试在 haskell 中实现一个协议解析器 而且我对这门语言还很陌生 特别是当涉及到 monad 时 我一直在使用binary 0 5 0 2 并描述了协议的标头和所有有效负载 我想要解析的消息如下所示 header payloa
  • 如何获取常量内存中的统计数据

    我有一个函数 它会创建一些随机的数值结果 我知道 结果将是 a 小 a b 约 50 范围内的整数a b 我想创建一个执行上述函数 1000000 次的函数 并计算每个结果出现的频率 该函数使用随机生成器来生成结果 问题是 我不知道如何在常
  • 是否有一个基于对象身份的、线程安全的记忆库?

    我知道记忆化似乎是堆栈溢出的 haskell 标签上的一个长期话题 但我think以前没有人问过这个问题 我知道 Haskell 有几个不同的 现成 记忆库 memo combinators 和 memotrie 包 利用涉及惰性无限数据结
  • 如何处理“恐慌:不可能的事情发生了”并在 Haskell 中继续

    我有以下代码 它使用 GHC API 加载模块并获取表达式的类型 typeObjects String gt String gt IO Type typeObjects modules objects do defaultErrorHand
  • 解析 PHOAS 表达式

    我想我理解 PHOAS 参数化高阶抽象语法 我明白了如何漂亮地打印一个表达式 参见http www reddit com r haskell comments 1mo59h phoas for free by edward kmett cc
  • 有没有办法在 Emacs 中使用 Djinn 自动生成 Haskell 代码?

    标题几乎说明了一切 我正在寻找这样的东西 f Int gt Bool gt Int f body Djinn 可以使用定理证明来通过证明该类型存在来生成此类函数的代码 我想知道 是否有现有的方法可以从 Emacs 中获取此功能 因此 我不需
  • 有什么方法可以在 do / while / let 块中打印出变量的类型吗?

    有没有办法打印出嵌套变量的推断类型ghci 考虑代码 let f g where g x Int x 那么 最好查询一下类型g e g t f g会打印出Int gt Int 您可以通过给出适当的错误类型注释并检查错误消息来诱骗此信息 Ma
  • 如何处理在组合下发生变化的类型?

    我最近读了一篇非常有趣的论文单调性类型 https infoscience epfl ch record 231867 files monotonicity types pdf其中描述了一种新的 HM 语言 该语言可以跟踪操作之间的单调性
  • Haskell 中的类型化抽象语法和 DSL 设计

    我正在 Haskell 中设计 DSL 我想要进行赋值操作 像这样的东西 下面的代码只是为了在有限的上下文中解释我的问题 我没有类型检查 Stmt 类型 data Stmt forall a Assign String Exp a Assi
  • 为什么 Haskell 中的点是从右向左排列的?

    如果我们有两个函数 f and g 然后在哈斯克尔h f g相当于h x f g x IE 这些函数从右到左应用于输入 有什么根本原因可以解释为什么它是从右到左 而不是从左到右吗 IE 他们为什么不做h f g相当于h x g f x 反而
  • Parsec 函数“parse”和类“Stream”的类型签名

    约束条件是什么 Stream s Identity t 下面的类型声明是什么意思 parse Stream s Identity t gt Parsec s a gt SourceName gt s gt Either ParseError
  • 为什么以下内容会并行运行而不是顺序运行?

    给定以下函数evalPair parPair and deepSeq分别 evalPair Strategy a gt Strategy b gt Strategy a b evalPair sa sb a b do a lt sa a b
  • Haskell:从后面访问列表

    今天我开始学习Haskell 我对函数式语言有点陌生 而且我非常喜欢 Haskell 然而 我有一个关于它的设计的问题困扰着我 从我到目前为止的理解来看 访问列表后面的元素似乎比访问前面的元素要复杂得多 类似于xs x where xs a

随机推荐