Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/10.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_Recursion_Permutation_Interleave - Fatal编程技术网

Haskell 我可以使用什么函数对另一个函数进行多个嵌套调用?

Haskell 我可以使用什么函数对另一个函数进行多个嵌套调用?,haskell,recursion,permutation,interleave,Haskell,Recursion,Permutation,Interleave,我需要以这种嵌套方式调用此perms函数: e = [1,3,7,10, 25,50] f = perms (perms (perms (perms (perms (perms [[]] e) e) e) e) e) e g = [[]] ++ f -- final set of permutations perms :: (Eq a, Ord a) => [[a]] -> [a] -> [[a]] -- set [a] is a set of existing perm

我需要以这种嵌套方式调用此
perms
函数:

e = [1,3,7,10, 25,50]
f = perms (perms (perms (perms (perms (perms [[]] e) e) e) e) e) e
g = [[]] ++ f -- final set of permutations 

perms :: (Eq a, Ord a) => [[a]] -> [a] -> [[a]] 
-- set [a] is a set of existing permutations and set [b] are the elements to add to [a] in all possible permutations
perms xss      [] = xss  -- no unique elements to create new permutations from
perms [xs]     ys = [xs ++ [y] | y <- ys \\ xs ]                         -- last list of xs in list xss 
perms (xs:xss) ys = [xs] ++ [ xs ++ [y] | y <- ys\\xs ] ++ perms xss ys 

我相信我可以在
perms
函数中添加另一个
Int
参数,通过p(n,r)计算r我想您正在寻找
foldl
,不是吗

foldl perms [[]] [e,e,e,e,e,e] == perms (perms (perms (perms (perms (perms [[]] e)e)e)e)e)e
或者如果
e
是固定的,您也可以使用
replicate

foldl perms [[]] (replicate 6 e) == perms (perms (perms (perms (perms (perms [[]] e)e)e)e)e)e
因此,在您的情况下,它的工作原理如下:

Prelude> take 10 $ foldl perms [[]] (replicate 6 e)
[[1],[1,3],[1,7],[1,10],[1,25],[1,50],[1,3],[1,3,7],[1,3,10],[1,3,25]]
这里有一个方法:

> foldr ($) [[]] (replicate 1 $ flip perms e)
[[1],[3],[7],[10],[25],[50]]

> foldr ($) [[]] (replicate 2 $ flip perms e)
[[1],[1,3],[1,7],[1,10],[1,25],[1,50],[3],[3,1],[3,7],[3,10],[3,25],[3,50],
 [7],[7,1],[7,3],[7,10],[7,25],[7,50],[10],[10,1],[10,3],[10,7],[10,25],
 [10,50],[25],[25,1],[25,3],[25,7],[25,10],[25,50],[50,1],[50,3],[50,7],
 [50,10],[50,25]]

> foldr ($) [[]] (replicate 6 $ flip perms e)
...............
这是怎么发生的?你有

f3 =                 perms   ( perms   ( perms  [[]]  e )  e )  e
   =                 perms' e ( perms' e ( perms' e  [[]] ))
   =                 perms' e $ perms' e $ perms' e $ [[]]
   = foldr ($) [[]] (perms' e : perms' e : perms' e : [])
   = foldr ($) [[]] (replicate 3 (perms' e))
   = foldr ($) [[]] (replicate 3 $ flip perms e)

perms' e xs = perms xs e
            = flip perms e xs
perms' e    = flip perms e
perms'      = flip perms
然后我们把
3
提取出来

所以这或多或少只是语法。(嗯,不是真的,但足够近了)

当然,我们也可以将
perm'
本身视为操作符

f3 =                    perms   ( perms   ( perms  [[]]  e )  e )  e
   =                    perms' e ( perms' e ( perms' e  [[]] ))
   =                    e `perms'` e `perms'` e `perms'` [[]]
   = foldr perms' [[]] (e    :     e    :     e    :     [])
   = foldr (flip perms) [[]] (replicate 3 e)
   = foldl perms [[]] (replicate 3 e)
甚至更短

顺便提一下,最后一段,
foldl
代码片段是一个罕见的例子,可以使用
foldl
,而不是
foldl'
。它首先用于构建嵌套的计算结构(嵌套的
perms
调用),然后通过Haskell的惰性计算运行


当我使用
($)
本身时,我把重点放在了代码的结构上,这在最后一段代码中没有出现,只是暗示了。

我会使用
迭代
,如

iterate (flip perms e) [[]] !! 6
使用Data.List库置换函数不起作用,因为除了(n=720)6元素置换之外,我还需要(720)5元素置换,(360)4元素置换,(120)3元素置换…,(6)1元素置换和空集解决方案。因为在这个游戏中,你可以使用任意选择的6个数字中的任意多或少数

我更愿意使用
置换
然后改进其结果,而不是自己重新实现整个过程,这不仅是因为
置换
的实现效率比我想象的要高。在这种情况下,对常规列表执行此操作非常简单,无需显式使用其长度。当然,这并不能解决你的直接问题(“如何将一个函数自身构造N次”),但我认为这是一个更好的解决方案,可以实现你的真正目标(“找到集合子集的排列”)

请注意,它完全符合小列表的规格。对于全套6个数字,它给出了1957种可能性。对吗

*Main> factorial n = product [1..n]
*Main> n `nPr` r = factorial n `div` factorial (n - r)
*Main> sum . map (6 `nPr`) $ [0..6]
1957

是的,有1957种方法可以从6个元素的总体中选择0个或更多元素的有序集合。

啊,复制!任何原因为什么
foldr
而不是
foldl
-我仍然只是把我的头折叠起来,我仍然需要做很多练习来自信地使用fold和foldr。我只是翻译你的代码,目的是为了它的语法等价物。“交织”有一个或多或少被接受的“编织”的意思,它是
[[a]->[a]
或者至少
[a]->[a]->[a]
。谢谢。当我有机会了解他的代码时,我会解构他的代码。
permutations
的源代码也使用了interweave内部函数,但它的作用让我感到困惑。感谢@radrow
e
在程序开始时被声明为常量,如果这就是你所说的固定,我不确定你所说的固定是什么意思。嗯,我的意思是,如果这个列表必须只包含esyes,那么它将始终是一个包含6个整数的列表。整数在每次运行时都可能更改,但总是整数。为什么?这显然是不正确的——我们需要知道索引是基于0的,
iterate
将首字母作为结果的开头,而不是
replicate
,后者只是简单地说明了它的功能。(如果OP想要1..6次重复的所有结果,那么当然,
iterate
就是门票)。@WillNess搞笑。对我来说,这更是不言而喻的正确。使用
foldr
,我必须在脑海中模拟一些小列表的作用,然后才能理解,啊!,
foldr
只是将一个函数应用于另一个函数的输出。然后这个复制专门用于迭代单个函数。。。然后我开始纳闷,为什么他们编写这个自定义递归而不是使用
迭代
?这让我双重猜测是否有聪明的事情正在发生,我错过了…嗯。到现在为止,我已经习惯了foldr,我只知道它生成了一系列reducer函数的嵌套应用程序(这正是OP想要的)。而且,
replicate
向我展示了什么,以及有多少——这就是我所指的,可能的一个错误回到
foldr
,是的,任何foldr都只是应用函数。我曾经意识到,
foldrfz=foldr($)z。map f=($z)。foldr(.)id。map f=(`appEndo`z)。foldMap(Endo.f)
所以我不需要再考虑它了。我不明白($),所以我看了看源代码,它说
f$x=fx
-好的,太好了,为什么要使用它?Hackage:“应用程序运算符。此运算符是多余的,因为普通应用程序(fx)与(f$x)的意思相同。但是,$具有较低的右关联绑定优先级,因此有时允许省略括号;例如:
f$g$hx=f(g(hx))
它在高阶情况下也很有用,例如
map($0)xs
,或
zipWith($)fs xs
。请注意($)在其结果类型中是可变多态的,因此
foo$True,其中foo::Bool->Int#
类型很好。“@wide#u-eyed#pull”为什么要使用它?因为作为foldr操作符,
foldr(…)…
,我们会写什么呢?,没有?空白?:)“levity”如果在代码中不使用“魔法散列”(如
Int#
),则无需担心。谢谢,这是一个学习练习,而不是“最佳实践”。在我尝试走路之前学习爬行。通过一些测试,我的方法可以做到
iterate (flip perms e) [[]] !! 6
import Control.Monad (filterM, (<=<))
import Data.List (permutations, tails)

subsets :: [a] -> [[a]]
subsets = filterM (const [False, True])

permutationsOfSubsets :: [a] -> [[a]]
permutationsOfSubsets = permutations <=< subsets
*Main> permutationsOfSubsets [1,2,3]
[[],[3],[2],[2,3],[3,2],[1],[1,3],[3,1],[1,2],[2,1],[1,2,3],[2,1,3],[3,2,1],[2,3,1],[3,1,2],[1,3,2]]
*Main> length . permutationsOfSubsets $ [1..6]
1957
*Main> factorial n = product [1..n]
*Main> n `nPr` r = factorial n `div` factorial (n - r)
*Main> sum . map (6 `nPr`) $ [0..6]
1957