【问题标题】:Haskell duplicate element at certain positionHaskell在特定位置重复元素
【发布时间】:2013-02-25 23:20:43
【问题描述】:

我想复制列表的第 n 个元素,而我对 haskell 的了解非常有限。 我尝试将列表分成两部分,然后获取第一部分的最后一个元素并将其粘贴在这些部分之间:

dupl n (x:xs) = (take n (x:xs)) ++ ( (x:xs) !! n) ++ (drop n (x:xs))

但我总是得到错误:

Prelude> :l f.hs
[1 of 1] Compiling Main             ( f.hs, interpreted )

f.hs:5:39:
   Occurs check: cannot construct the infinite type: a0 = [a0]
   In the first argument of `(:)', namely `x'
   In the first argument of `(!!)', namely `(x : xs)'
   In the first argument of `(++)', namely `((x : xs) !! n)'
Failed, modules loaded: none.

谁能告诉我我做错了什么?

【问题讨论】:

    标签: list haskell list-comprehension


    【解决方案1】:

    list !! n 返回一个列表元素,而不是一个列表。 ++ 只能连接列表;您不能使用++ 将列表元素添加到列表中。

    更正式地说,!! 有一个类型:

    (!!) :: [a] -> Int -> a
    

    这意味着它接受as 和Int 的列表,并返回a。另一方面,++ 的类型为:

    (++) :: [a] -> [a] -> [a]
    

    这意味着它接受两个as 列表并返回一个as 的新列表。所以你可以看到++ 接受列表,但!! 不返回列表,所以你不能像那样将它们链接在一起。


    我们如何解决这个问题?您需要将元素 list !! n 放入一个列表中,以便将其连接到其他两个列表,而不会让类型检查器产生混乱。

    这应该可以解决问题:

    dupl n l = (take n l) ++ [l !! n] ++ (drop n l)
    

    等效地,将所选元素添加到右侧列表,并将其连接到原始列表的另一半:

    dupl n l = (take n l) ++ ((l !! n):(drop n l))
    

    警告讲师:与@Marimuthu 的建议不同,如果n 是越界索引,上述两个函数都会引发异常。异常来自!!

    【讨论】:

      【解决方案2】:

      如果您选择了错误的索引,请注意购买者,但是——

      dupN n xs = let (first, x:rest) = splitAt (n-1) xs in first ++ x:x:rest
      

      【讨论】:

      • 这是最漂亮的。我想in first ++ [x,x] ++ rest 更好,我想。
      • 谢谢!我也很喜欢你的建议。
      【解决方案3】:

      你也可以使用splitAt:

      dupl n xs = first ++ take 1 rest ++ rest where (first, rest) = splitAt (n - 1) xs 
      

      如果n 越界,这不会中断。

      【讨论】:

        猜你喜欢
        • 2013-06-05
        • 2013-08-17
        • 2017-05-13
        • 1970-01-01
        • 1970-01-01
        • 2016-04-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多