Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 如何使用带保护的尾部递归将列表拆分为两个?_Haskell_Tuples_List Comprehension - Fatal编程技术网

Haskell 如何使用带保护的尾部递归将列表拆分为两个?

Haskell 如何使用带保护的尾部递归将列表拆分为两个?,haskell,tuples,list-comprehension,Haskell,Tuples,List Comprehension,如果我有一个列表,比如说[1,2,3,4],我如何创建两个列表的元组,以便第一个列表包含奇数元素,第二个列表包含偶数元素。如何使用尾部递归来实现这一点 例如: 我基本上需要两个本地列表,它们由每个保护壳组成,最后放在一个元组中。尾部递归函数是这样的函数,其中函数的最终结果是对同一个函数的回调。在Haskell中,这意味着等式的右侧必须是对函数的调用。那么比如说,, f(x:xs)n=fxs(n+1) 尾部是递归的,而 f'(x:xs)=1+f'xs 不是-因为虽然存在递归调用,但它不是函数的结果

如果我有一个列表,比如说
[1,2,3,4]
,我如何创建两个列表的元组,以便第一个列表包含奇数元素,第二个列表包含偶数元素。如何使用尾部递归来实现这一点

例如:


我基本上需要两个本地列表,它们由每个保护壳组成,最后放在一个元组中。

尾部递归函数是这样的函数,其中函数的最终结果是对同一个函数的回调。在Haskell中,这意味着等式的右侧必须是对函数的调用。那么比如说,, f(x:xs)n=fxs(n+1) 尾部是递归的,而 f'(x:xs)=1+f'xs 不是-因为虽然存在递归调用,但它不是函数的结果。相反,(+)的计算是结果

对于您的代码,这意味着您需要以下内容:

sumt_tr :: [Int] -> ([Int],[Int])
sumt_tr xs = go xs ([],[])
    where
    go [] (os,es) = (reverse os,reverse es)
    go (x:xs) (os,es) | x `mod` 2 == 0 = go xs (os,x:es)
                      | otherwise      = go xs (x:os,es)

这里,函数
go
(sumt_tr的本地)是尾部递归的,因为
go
的每个方程都直接再次调用
go
。请注意,为了将
go
编写为尾部递归,我需要通过将其作为第二个参数传递来累加结果,当到达列表末尾时将返回该结果。

使用显式递归最直接的方法是使用尾部递归辅助函数,为结果列表使用两个累加器:

sumt :: [Int] -> ([Int], [Int])
sumt = go [] []
  where

    -- Each recursive call is directly to ‘go’,
    -- so it’s tail-recursive.
    go os es (x:xs)
      | x `mod` 2 == 0 = go os (x:es) xs
      | otherwise = go (x:os) es xs

    -- In the base case, it returns a tuple with
    -- the accumulated results in the proper order.
    go os es [] = (reverse os, reverse es)
一种更简单的方法是使用
数据中的
分区
函数。List

sumt :: (Integral a) => [a] -> ([a], [a])
sumt = partition odd
如果查看
分区的定义,它不是通过显式递归实现的,而是通过
foldr
实现的。这里有
odd
内联:

sumt = foldr select ([], [])
  where
    select x ~(os, es)
      | odd x = (x:os, es)
      | otherwise = (os, x:es)

这具有流式处理的优点:它不包括在最后反转累积列表的O(n)步骤,它只是以增量方式生成结果。

您确定要将其设置为尾部递归吗?为什么?此外,您尝试的代码不是尾部递归。
//Comment
不是Haskell注释。使用
--Comment
。我正在尝试使用保护和尾部递归来解决这个问题。是否有任何方法可以生成空元组和空列表,并使用递归
偶数
奇数
填充它们是前奏曲中的函数
即使是4
也会返回
True
。好的,为了这样做,我必须提供元组([],[])的初始值。我想我可以先创建列表,然后将它们打包成元组。类似->迭代初始列表,每次取1个元素,插入两个本地列表变量中的一个,然后将它们放入元组中。@Bercoviciarian是的,您需要累加器的初始值。在执行每个尾部递归调用时,通过向累加器添加新值进行累加。在这种情况下,如果初始值是所谓的“单位”值(即,它充当特定操作的标识),并且该操作是单像(二进制和关联),则可以用
mempty
替换初始值。因此,上面代码中对
go-xs([],[])
的调用可以替换为
go-xs-mempty
。顺便说一句,关于Haskell中未被理解的幺半群真的很值得一读。你能提供进一步阅读的资料吗?到目前为止,我一直在用我的直觉涉猎Haskell,但我知道在事物如何工作方面有具体的集合论数学,为了更好地理解它。@Bercoviciarian有很多很好的在线资源。(向你学习Haskell)是一个很好的资源。还有,它有读者嵌入注释的好处,但现在有点旧,后面章节中的一些代码有点过时(在这种情况下,阅读注释帮助,因为更新代码的建议已发布)。如果你想花钱,那是我绝对喜欢的。谢谢你的回答,先生!
sumt :: (Integral a) => [a] -> ([a], [a])
sumt = partition odd
sumt = foldr select ([], [])
  where
    select x ~(os, es)
      | odd x = (x:os, es)
      | otherwise = (os, x:es)