【问题标题】:Duplicating elements in a list复制列表中的元素
【发布时间】:2014-11-05 02:16:53
【问题描述】:

我有一个列表,例如 [1, 2, 3, 4, 5],我必须复制列表中的每个元素以形成像 [1, 1, 2, 2, 3, 4, 4 这样的列表, 5, 5]。

作为提示,我们提到了 concat 函数,它将列表列表扁平化为单个列表。但是为了尝试了解如何更好地在 Haskell 中进行此操作,我正在尝试手动进行。这是我的尝试:

duplicate :: [a] -> [a]
duplicate [] = []
duplicate (x:xs) =  x : (x:xs) duplicate xs

带有错误信息:

Couldn't match expected type `((a0 -> Bool) -> [a0] -> [a0])
                                  -> [a] -> [a]'
                with actual type `[a]'
    The function `x : xs' is applied to two arguments,
    but its type `[a]' has none
    In the second argument of `(:)', namely `(x : xs) myTakeWhile xs'
    In the expression: x : (x : xs) myTakeWhile xs
Failed, modules loaded: none.

我的想法是,你将列表的头部cons到整个列表,然后递归调用这个列表尾部的函数。以伪代码为例:

duplicate [1, 2, 3]

1 : [1, 2, 3] duplicate [2, 3]

2 : [2, 3] duplicate [3]

3: [3] duplicate []

return list [1, 1, 2, 2, 3, 3]

这是解决此问题的惯用方式吗?我在语法上的尝试中哪里出错了?我不是在寻找替代的、更有效的代码解决方案,我只是想习惯于用函数式的方式解决问题,而不是用命令式的方式看待事物。

谢谢!

【问题讨论】:

  • x y 始终表示“将函数x 应用于参数y”。在[1, 2, 3] function 中,[1, 2, 3] 不是函数,因此会出现类型错误。
  • 你的想法是对的,但是你错误地应用了函数。代码尝试将列表视为您将myTakeWhile 和列表传递给的函数。也许,先复制尾部,然后将头部附加两次。
  • myTakeWhile 是一个复制错误,试图递归调用重复。已编辑。

标签: haskell


【解决方案1】:

您要查找的定义是:

duplicate :: [a] -> [a]
duplicate [] = []
duplicate (x:xs) =  x : x : duplicate xs

由于: 是一个右结合运算符,您可以将最后一个备选方案解读为

duplicate (x:xs) =  x : (x : (duplicate xs))

或作为

duplicate (x:xs) =  (:) x ((:) x (duplicate xs))

请记住[1, 2, 3] 只是1 : 2 : 3 : [] 的缩写,当duplicate 应用于[1, 2, 3] 时,将使用第二种选择,因为它匹配x : xs 模式(即x = 1 和@ 987654331@)。您希望结果以头部开始两次(这是定义的 x : x : ... 部分),并以重复的尾部(... : duplicate xs 部分)继续。

【讨论】:

  • 所以我的思维方式行得通!只是语法有点偏离,谢谢!
  • @Bradley 我真的希望 Haskell 的列表语法不会让想要使用 Haskell 的人完全混淆:/
  • Haskell 有一个巨大的学习曲线,特别是对于那些在命令式语言上长大的人。我发现我大部分时间都在弄清楚如何以语法正确的方式表达我的想法
  • 通过结构化递归的另一种说法是:duplicate = foldr (\a b -> a:a:b) []
猜你喜欢
  • 2013-12-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-31
  • 1970-01-01
  • 2012-11-27
  • 1970-01-01
相关资源
最近更新 更多