List 创建每个位置都有新元素的列表列表
我是haskell的新手,我想知道如何在haskell列表的每个位置插入一个值,并返回包含每个位置值的子列表。例如:List 创建每个位置都有新元素的列表列表,list,haskell,insert,List,Haskell,Insert,我是haskell的新手,我想知道如何在haskell列表的每个位置插入一个值,并返回包含每个位置值的子列表。例如: insert' :: a -> [a] -> [[a]] insert' a [] = [[a]] insert' a list = ?? 要获得类似于: insert' 7 [1,2,3] = [[7,1,2,3],[1,7,2,3],[1,2,7,3],[1,2,3,7]] P>空列表的情况是自然的,让我们来看看插入'yxSS@(x:xs)。我们基本上需要涵
insert' :: a -> [a] -> [[a]]
insert' a [] = [[a]]
insert' a list = ??
要获得类似于:
insert' 7 [1,2,3] = [[7,1,2,3],[1,7,2,3],[1,2,7,3],[1,2,3,7]]
<> P>空列表的情况是自然的,让我们来看看<代码>插入'yxSS@(x:xs)。我们基本上需要涵盖两种情况:
y
出现在x
前面。然后我们可以使用y:xss
y
出现在x
之后的某个位置。因此,我们只需将其插入列表的其余部分,并确保x
是map(x:)
的第一个元素x
,ys=[y1,y2,…,yn]
,第一次我们将把它作为头插入,这意味着我们可以构造x:ys
。对于结果列表的第二个元素,我们要构造一个列表[y1,x,y2,…,yn]
。我们可以像这样做y1:x:y2s
。接下来的列表都将具有结构y1:…
问题是:我们如何编写一个递归结构来跟踪我们希望将元素放入头部的事实。我们可以使用一个函数:我们从一个函数id
开始。如果我们现在调用id(x:ys)
,那么我们当然会生成列表(x:ys)
但是,我们可以基于id
函数,构造一个新函数id2=\z->id(y1:z)
。因此,此函数将把y1
放在列表的头部,然后添加我们称之为id2
的列表作为尾部。接下来我们可以构造id3=\z->id2(y2:z)
。这将把y1
和y2
作为第一个元素,然后是尾部z
因此,我们可以将其转换为以下递归格式:
insert' :: a -> [a] -> [[a]]
insert' x = go id
where go d [] = [d [x]]
go d ys@(yh:yt) = (d (x : ys)) : go (d . (yh :)) yt
因此,我们将insert'
重定向到go
,其中初始差异列表只是id
函数。每次我们检查是否已到达给定列表的末尾。如果是这种情况,我们将返回basecase:我们在差异列表上调用[x]
(作为tail),从而构建一个列表,在其中我们将x
作为最后一个元素追加
如果我们还没有到达最后一个元素,我们将首先发出d(x:ys)
:我们将x
前置到列表中,并将其作为差异列表d
的参数提供<代码>d将在y1:y2:yk
直到插入x
为止。此外,我们在列表的尾部递归调用go(d.(yh:))yt
:因此我们构造了一个新的差异列表,我们在这里插入(yh:)
,作为列表的尾部。因此,我们产生了一个带有一个参数的新函数:yh
元素后面的尾部
此函数产生预期的结果:
*Main> insert' 4 []
[[4]]
*Main> insert' 4 [1,2,5]
[[4,1,2,5],[1,4,2,5],[1,2,4,5],[1,2,5,4]]
*Main> insert' 7 [1,2,3]
[[7,1,2,3],[1,7,2,3],[1,2,7,3],[1,2,3,7]]
你也可以这样做
import Data.List
spread :: a -> [a] -> [[a]]
spread x xs = zipWith (++) (inits xs) ((x:) <$> tails xs)
*Main> spread 7 [1,2,3]
[[7,1,2,3],[1,7,2,3],[1,2,7,3],[1,2,3,7]]
*Main> spread 7 []
[[7]]
spread :: a -> [a] -> [[a]]
spread x = zipWith (++) <$> inits <*> fmap (x:) . tails
在本例中,我们将fmap
类型为[[a]]->[[a]]->[[a]]->[[a]]
的zipWith(++)
函数应用于fmap(x:)。尾部
它可能会变得更无意义,但通读起来会变得更复杂(至少对我来说是这样)。在我看来,这是最好的。@Zeta
之前
和之后
与顺序无关,而是与列表中的位置有关,没有预先假设a
一个我修改过的Ord
@Zeta的实例出现,希望表明这一点。我不是以英语为母语的人,如果有任何建议表达这一点,我将不胜感激。在部分(f y xs)中,这样做的目的是使用列表调用函数,而不使用第一个元素,对吗?@john yes。递归是关于找到子问题,模式的。非常感谢!!看到答案是如此简单真是难以置信,我想我需要大量的练习才能掌握这门语言
spread :: a -> [a] -> [[a]]
spread x = zipWith (++) <$> inits <*> fmap (x:) . tails