haskell - 如何在没有映射或列表理解的情况下在 Haskell 中编写简单的递归双循环
问题描述
我试图理解递归,所以我想我会用原始的 Haskell 编写一个简单的双 for 循环(没有列表推导,没有映射等)。
给定 i 和 j 产生以下..
rTest01 2 5
[[2,5],[2,4],[2,3],[2,2],[2,1],[1,5],[1,4],[1,3],[1,2],[1,1]]
我的代码有效,但看起来并不漂亮.. 每次“i”更改时,我都必须添加一个额外的参数来重新加载“j”。
有没有更简洁的写法?
rTest01 :: Int -> Int -> [[Int]]
rTest01 i j =
[[i,j]] ++ rTest01' j i (j-1)
rTest01' :: Int -> Int -> Int -> [[Int]]
rTest01' origJ i 0 = rTest01' origJ (i-1) origJ
rTest01' _ 0 _ = []
rTest01' origJ i j =
[[i,j]] ++ rTest01' origJ i (j-1)
解决方案
这是内部递归的一个很好的用例。就像在 Python 或 Java 中,我们可能有一个私有递归函数,它只被一个公共非递归函数调用(后者不接受额外的“帮助”参数),我们可以做同样的事情在 Haskell 中使用嵌套范围。
example :: Int -> Int -> [(Int, Int)]
example iorig jorig = go iorig jorig
where go 0 _ = []
go i 0 = go (i - 1) jorig
go i j = (i, j) : go i (j - 1)
虽然我非常感谢您的递归练习,并且我确实强调编写这样的代码是一个非常好的练习,因为它练习了更复杂的 Haskell 编码所需的许多基本技能,请记住这一点,即使按照我的方式编写上面,这不是惯用的 Haskell。如果我在生产中编写这个函数,我会写
example :: Int -> Int -> [(Int, Int)]
example i j = reverse $ (,) <$> [1..i] <*> [1..j]
(删除reverse
如果我们不关心订单)
递归是一种非常方便的技能,但它并不总是解决方案。事实上,在 Haskell 中,我们通常可以构建其他几个抽象来使我们的代码更简单,例如上面示例中的应用程序和 monad。
祝你好运,编码愉快!:)
推荐阅读
- python - 有没有更好的方法从列表中检索日期时间对象?
- python - 如何从由制表符和换行符分隔的数据字符串创建 dask 数据帧
- r - 在 R 中使用 dplyr 过滤时返回整个组
- excel - 具有 VLOOKUP 功能的 ComboBox-Textbox 链接值仅保留某些特定范围(不是所有范围)
- spring-mvc - 如何在配置类中使用 RedisMessageListenerContainer
- css - 我可以对所有元素或父元素使用'/deep/'吗
- android - 删除单个 SQlite 行 RecyclerView onSwiped
- javascript - 如何检测 Web Share Target API 的可用性?
- node.js - Bcrypt密码比较不显示结果
- docker - 需要在 docker 容器中使用脚本运行服务