Haskell 从不可遍历且无递归的

Haskell 从不可遍历且无递归的,haskell,recursion,enums,traversable,Haskell,Recursion,Enums,Traversable,我可以通过映射Map、mapM或折叠foldl、foldM或另一个可遍历的数据结构来构建作为可遍历类型类成员的数据结构,例如List或Map 但是,我经常遇到需要使用Num typeclass成员(例如Integer)构建可遍历数据结构的情况 我通常的方法是使用递归操作构建列表,例如: import Data.List bar :: Int -> [[Int]] bar n = unfoldr step 1 where step k | k > n = Nothing

我可以通过映射Map、mapM或折叠foldl、foldM或另一个可遍历的数据结构来构建作为可遍历类型类成员的数据结构,例如List或Map

但是,我经常遇到需要使用Num typeclass成员(例如Integer)构建可遍历数据结构的情况

我通常的方法是使用递归操作构建列表,例如:

import Data.List

bar :: Int -> [[Int]]
bar n = unfoldr step 1
  where step k | k > n     = Nothing
               | otherwise = Just (replicate k k, k + 2)

main = do
  print $ bar 10
  -- [[1],[3,3,3],[5,5,5,5,5],[7,7,7,7,7,7,7],[9,9,9,9,9,9,9,9,9]]
foo::Integer->[Integer]->[Integer] 福安财政司司长 |m<2=fs |rem m 2==0=foo m-1 m:fs |否则=foo m-1 fs 式中m=绝对值n 此函数返回可被2整除且介于2和n之间(含2和n)的整数的绝对值


使用上面的示例,是否有一种惯用的方法可以从不可遍历的列表中构建列表而不使用递归?

由于您要从2到n,并过滤掉值,请使用专为此设计的筛选函数:

foo::Integer->[Integer] foo n=filter\x->x`mod`2==0[2..n]
由于要从2到n,并过滤掉值,因此使用专为此设计的过滤函数:

foo::Integer->[Integer] foo n=filter\x->x`mod`2==0[2..n]
您正在寻求一种从不可遍历对象构建列表而不使用递归的方法,但我认为这并不是您真正想要的。毕竟,任何遍历都将使用递归——您认为map和foldl是如何实现的?我认为你要问的更精确的问题是,是否有一个众所周知的函数或内置方式来表示所谓的数字折叠,其中递归是幕后的,还是隐式的,而不是像你的foo示例中那样显式的

实现这一点的一个简单方法是自己编写一个foldNum函数。例如:

foldNum::Num n=>n->a->a->n->a foldNum fn=fn foldNum fn-1 然后,您可以将foo定义为:

foo::Integer->[Integer] foo=反向。福尔德纳姆:走吧。防抱死制动系统 哪里 去n a | n<2=[] |rem n2==0=n:a |否则=a 如果你对此有点失望,我理解为什么:使用foldNum的这个定义,你并没有真正节省很多钱。事实上,我上面给出的定义甚至没有内置的基本情况。折叠一个数字的问题是有很多方法!你可以在每一步上减去或加上任何数量,并且没有明确的停止位置。零可能看起来是一个自然的停止位置,但这仅适用于非负数。一种方法是尝试使我们的foldNum更加通用。那么:

foldNum::n->a->a->n->Bool->n->n->a->n->a 折叠f停止步骤a n |停止n=a |否则=折叠f停止步骤f n a步骤n 现在,我们可以将foo写成:

foo::Integer->[Integer] foo=foldNum\xa->如果偶数为x,则x:a否则a<2减去1[]。防抱死制动系统 也许这就是你要找的

脚注: 正如列表可以向左或向右折叠一样,我们也可以用两种不同的方式折叠数字。您可以将上述foldNum定义的最后一行替换为::

|否则=f n$foldNum f停止步骤a步骤n
例如,对于foo来说,这两者之间的区别是结果列表的顺序。

您正在寻求一种不使用递归从不可遍历对象构建列表的方法,但我认为这不是您真正想要的。毕竟,任何遍历都将使用递归——您认为map和foldl是如何实现的?我认为你要问的更精确的问题是,是否有一个众所周知的函数或内置方式来表示所谓的数字折叠,其中递归是幕后的,还是隐式的,而不是像你的foo示例中那样显式的

实现这一点的一个简单方法是自己编写一个foldNum函数。例如:

foldNum::Num n=>n->a->a->n->a foldNum fn=fn foldNum fn-1 然后,您可以将foo定义为:

foo::Integer->[Integer] foo=反向。福尔德纳姆:走吧。防抱死制动系统 哪里 去n a | n<2=[] |rem n2==0=n:a |否则=a 如果你对此有点失望,我理解为什么:使用foldNum的这个定义,你并没有真正节省很多钱。事实上,我上面给出的定义甚至没有内置的基本情况。折叠一个数字的问题是有很多方法!你可以在每一步上减去或加上任何数量,并且没有明确的停止位置。零可能看起来是一个自然的停止位置,但这仅适用于非负数。一种方法是尝试使我们的foldNum更加通用。那么:

foldNum::n->a->a->n->Bool->n->n->a->n->a 折叠f停止步骤a n |停止n=a |否则=折叠f停止步骤f n a步骤n 现在,我们可以将foo写成:

foo::Integer->[Integer] foo=foldNum\x a->如果偶数x,则x: a否则a<2减去1[]。防抱死制动系统 也许这就是你要找的

脚注: 正如列表可以向左或向右折叠一样,我们也可以用两种不同的方式折叠数字。您可以将上述foldNum定义的最后一行替换为::

|否则=f n$foldNum f停止步骤a步骤n
例如,对于foo,这两个函数的区别在于结果列表的顺序。

我认为您可能要查找的是Data.list中的库函数unformer。签名如下:

unfoldr :: (b -> Maybe (a, b)) -> b -> [a]
它从类型为b的值生成一个列表[a],该值是不可遍历的。它通过重复地将其第一个参数应用于b值来获得要添加到列表中的新a值和下一次调用的更新b值,直到没有任何结果结束列表

注意,它不允许在不生成任何as的情况下跳过某些bs,也不允许为单个b生成多个as。但是,您可以通过返回列表列表,然后连接来绕过该限制。因此,您的foo示例如下所示:

foo = concat . unfoldr step
  where step n | m < 2 = Nothing  -- time to stop
               | rem m 2 == 0 = Just ([m], m-1)  -- return one element
               | otherwise    = Just ([], m-1)   -- return no elements
          where m = abs n

我想您可能正在寻找Data.List中的库函数Unfolder。签名如下:

unfoldr :: (b -> Maybe (a, b)) -> b -> [a]
它从类型为b的值生成一个列表[a],该值是不可遍历的。它通过重复地将其第一个参数应用于b值来获得要添加到列表中的新a值和下一次调用的更新b值,直到没有任何结果结束列表

注意,它不允许在不生成任何as的情况下跳过某些bs,也不允许为单个b生成多个as。但是,您可以通过返回列表列表,然后连接来绕过该限制。因此,您的foo示例如下所示:

foo = concat . unfoldr step
  where step n | m < 2 = Nothing  -- time to stop
               | rem m 2 == 0 = Just ([m], m-1)  -- return one element
               | otherwise    = Just ([], m-1)   -- return no elements
          where m = abs n

这里的目标到底是什么?是不是要重写foo函数而不使用递归?你能用英语解释一下foo函数应该做什么吗?foldr可以为可折叠的数据结构生成一个lost。例如,在任意可折叠数据结构上执行toList的一种简单方法是foldr:[]。@Aplet123我想了解如何在不使用递归的情况下处理这类问题,以此为例-但这里的目标是重写特定的示例函数foo。将更新问题以解释函数的作用。此特定函数可以以非递归方式编写为\n fs->[2,4..n]++fs,但在不知道函数作用的情况下,无法对某些常规函数执行此类转换。对于不太重要的函数,使其非递归可能更困难。这里的目标是什么?是不是要重写foo函数而不使用递归?你能用英语解释一下foo函数应该做什么吗?foldr可以为可折叠的数据结构生成一个lost。例如,在任意可折叠数据结构上执行toList的一种简单方法是foldr:[]。@Aplet123我想了解如何在不使用递归的情况下处理这类问题,以此为例-但这里的目标是重写特定的示例函数foo。将更新问题以解释函数的作用。此特定函数可以以非递归方式编写为\n fs->[2,4..n]++fs,但在不知道函数作用的情况下,无法对某些常规函数执行此类转换。对于不那么琐碎的函数,使它们非递归可能更困难。是的,这正是我想要的,谢谢!关于这个主题,你有什么推荐的阅读材料吗?我手头上没有任何链接可以推荐,但我建议查找的一个关键词是变形。反同构是褶皱概念的推广。在对折叠变形的搜索中,出现了两篇看起来不错的博客文章。是的,这正是我想要的,谢谢!关于这个主题,你有什么推荐的阅读材料吗?我手头上没有任何链接可以推荐,但我建议查找的一个关键词是变形。反同构是褶皱概念的推广。在对折叠变形的搜索中,出现了几篇看起来不错的博客文章。