6

我正在自学 Haskell,并且在我的书中遇到了一个问题,该问题要求我定义一个函数 insert,该函数接受一个正整数n、元素y和一个在列表中的每个元素之后xs插入指定元素的列表。yn

我相信模式匹配可能是一个很好的方法,但我还没有真正理解它的含义

insert :: Int -> Char -> [a] -> [a]
insert 0 y xs = xs
insert n y [] = []
insert n y (x:xs)

该功能应如何工作的示例:

insert 2 'X' "abcdefghijk" = "abXcdXefXghXijXk"

在这一点上,我已经处理了基本情况,但我不知道如何从这里开始。

有任何想法吗?谢谢

4

4 回答 4

5

在最后一种情况下,取列表的 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)
于 2012-09-30T07:59:57.210 回答
4

可以使用库函数来发挥自己的优势。

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]那么ais 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 个元素放入结果中两次

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。而且您不必将索引放入结果中。

于 2012-09-30T08:04:22.587 回答
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

如果要在最后插入,你想要什么行为?在这里,我通过 put countdown 0 xsbefore优先插入而不是完成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?|"
于 2012-09-30T08:01:37.160 回答
1
ins n y xs = zip xs (cycle [1..n]) >>= f where
  f (x,k) = if k == n then [x,y] else [x] 

zip部分将循环“索引”附加到列表的元素,例如 forn = 3xs = "abcdefg"我们得到[('a',1),('b',2)('c',3)('d',1)('e',2)('f',3)('g',1)]。现在(>>=)(与列表的情况相同concatMap)用于f将每一对映射回原始元素,除非我们有循环的最后一个索引:在这种情况下,我们也插入一个额外的分隔元素y

于 2012-09-30T21:41:24.700 回答