我正在自学Haskell,我在书中遇到了一个问题,要求我定义一个函数插入,它带有一个正整数n
,元素y
和一个列表{ {1}}在列表中的每个xs
元素之后插入指定的元素y
。
我相信模式匹配可能是一个很好的方法,但我还没有真正理解它的含义
n
该功能应如何运作的一个例子:
insert :: Int -> Char -> [a] -> [a]
insert 0 y xs = xs
insert n y [] = []
insert n y (x:xs)
此时我已经处理了基本案例,但我不知道如何从这里开始。
有什么想法吗?感谢
答案 0 :(得分:4)
在最后一种情况下,取n个列表元素,插入y的单个列表,然后在删除列表的前n个元素后追加调用函数的结果。
insert :: Int -> Char -> [a] -> [a]
insert 0 y xs = xs
insert n y [] = []
insert n y xs
| length xs < n = xs
| otherwise = take n xs ++ [y] ++ insert n y (drop n xs)
答案 1 :(得分:3)
你可以编写一个辅助函数,当它变为零时倒计时并重置。
insert :: Int -> a -> [a] -> [a]
insert n y xs = countdown n xs where
countdown 0 xs = y:countdown n xs -- reset to original n
countdown _ [] = []
countdown m (x:xs) = x:countdown (m-1) xs
如果是时候插入,你想要什么行为?
在此,我通过在countdown 0 xs
之前添加countdown _ []
来优先插入完成。
如果你想在最后跳过插入,你怎么能重写呢?
样本用法:
*Main> insert 3 '|' "Hello Mum, erm... can I borrow £20000 please?"
"Hel|lo |Mum|, e|rm.|.. |can| I |bor|row| £2|000|0 p|lea|se?|"
答案 2 :(得分:3)
可以使用库函数。
import Data.List
insertAtN n y xs = intercalate [y] . groups n $ xs
where
groups n xs = takeWhile (not.null) . unfoldr (Just . splitAt n) $ xs
当然,如果您将Char
插入到[a]
类型的列表中,那么a
就是Char
,因为在Haskell中,列表的所有元素都是相同的类型。
为了帮助您更直接地理解这一点,让我们首先看一下列表的副本:
copyList (x:xs) = x : copyList xs
copyList [] = []
现在假设您为要复制的每个元素添加索引值(重新实现zip xs [1..]
):
copyIdxList xs = go 1 xs where
go i (x:xs) = (x,i) : go (i+1) xs
go _ [] = []
现在我们在处理每个元素时有一个索引值,我们可以使用它,比如说,将列表的每个第10个元素放入结果中: p>
copyIdxTenthTwice xs = go 1 xs where
go i (x:xs) | i==10 = (x,i) : (x,i) : go 1 xs
go i (x:xs) = (x,i) : go (i+1) xs
go _ [] = []
看看我要去哪里?您可以在那里插入x
,而不是复制y
。而且您不必将索引放入结果中。
答案 3 :(得分:1)
ins n y xs = zip xs (cycle [1..n]) >>= f where
f (x,k) = if k == n then [x,y] else [x]
zip
部分将循环“索引”附加到列表的元素,例如对于n = 3
和xs = "abcdefg"
,我们得到[('a',1),('b',2)('c',3)('d',1)('e',2)('f',3)('g',1)]
。现在(>>=)
(在列表的情况下与concatMap
相同)使用f
将每一对映射回原始元素,除非我们有一个循环的最后一个索引:在这种情况下,我们还插入了一个额外的分隔符元素y
。